# Radio / Radio

> Mutually exclusive options with coss ui's design over native radios.

Page: https://componentes-lovat.vercel.app/c/radio/  
License: MIT · Design: coss ui (MIT) · radio-group.tsx  
Requires: tokens.css  
Context: ambos · Density: media · Tone: sobria

## Files

- Tokens (once): https://componentes-lovat.vercel.app/tokens.css
- HTML: https://componentes-lovat.vercel.app/raw/radio/radio.html
- CSS: https://componentes-lovat.vercel.app/raw/radio/radio.css
- Everything in one file: https://componentes-lovat.vercel.app/r/radio.html

Dark theme: add class `dark` to `<html>`.

## When to use

- For 2 to 6 visible options.

## When not to use

- If several can be chosen: use checkboxes.

## Accessibility

Roles: radio, radiogroup

| Keys | Action |
|---|---|
| ↑ / ↓ | Chooses the previous or next option |
| Tab | Enters and leaves the group |

- Native radios sharing a name: one Tab stop and arrow keys with no JavaScript.

## Code

```html
<fieldset class="c-radio-group">
  <legend class="c-radio-group__legend">Envío</legend>
  <label class="c-radio-label c-radio-label--top"><span class="c-radio"><input class="c-radio__input" type="radio" name="ship" value="std" checked><span class="c-radio__indicator"></span></span><span class="c-radio-label__text">Estándar <span class="c-radio-label__description">3 a 5 días · gratis</span></span></label>
  <label class="c-radio-label c-radio-label--top"><span class="c-radio"><input class="c-radio__input" type="radio" name="ship" value="exp"><span class="c-radio__indicator"></span></span><span class="c-radio-label__text">Express <span class="c-radio-label__description">24 horas · S/ 15</span></span></label>
  <label class="c-radio-label c-radio-label--top"><span class="c-radio"><input class="c-radio__input" type="radio" name="ship" value="int" disabled><span class="c-radio__indicator"></span></span><span class="c-radio-label__text">Internacional <span class="c-radio-label__description">No disponible</span></span></label>
</fieldset>
```

```css
/* radio · Componentes (MIRÓ Labs). Diseño de coss ui (MIT, © coss.com, antes Origin UI).
   Generado por tools/build_css.py desde radio.tw.json. No editar a mano. Necesita tokens.css. */
.c-radio__indicator{position:absolute}
.c-radio{position:relative}
.c-radio__indicator{inset:-1px}
.c-radio-group__legend{margin-bottom:calc(var(--spacing)*1)}
.c-radio-group{display:flex}
.c-radio__indicator{display:flex}
.c-radio{display:inline-flex}
.c-radio-label{display:inline-flex}
.c-radio{width:calc(var(--spacing)*4.5);height:calc(var(--spacing)*4.5)}
.c-radio__indicator{width:calc(var(--spacing)*4.5);height:calc(var(--spacing)*4.5)}
.c-radio{flex-shrink:0}
.c-radio-group{flex-direction:column}
.c-radio{align-items:center}
.c-radio__indicator{align-items:center}
.c-radio-label{align-items:center}
.c-radio{justify-content:center}
.c-radio__indicator{justify-content:center}
.c-radio-label{gap:calc(var(--spacing)*2)}
.c-radio-group{gap:calc(var(--spacing)*3)}
.c-radio{border-radius:3.40282e38px}
.c-radio__indicator{border-radius:3.40282e38px}
.c-radio{border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background)}
.c-radio-group__legend{font-size:var(--text-base);line-height:calc(var(--spacing)*4.5)}
.c-radio-label{font-size:var(--text-base);line-height:calc(var(--spacing)*4.5)}
.c-radio-label__description{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}
.c-radio-group__legend{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}
.c-radio-label{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}
.c-radio-label__description{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}
.c-radio-group__legend{color:var(--foreground)}
.c-radio-label{color:var(--foreground)}
.c-radio-label__description{color:var(--muted-foreground)}
.c-radio{--tw-shadow-alpha:5%;--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
@supports (color:lab(0% 0 0)){
.c-radio{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,lab(0% 0 0/.05))}
}
.c-radio{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-outline-style:none;outline-style:none}
.c-radio:not(:is(.dark *)){background-clip:padding-box}
.c-radio:before{content:var(--tw-content);pointer-events:none;content:var(--tw-content);position:absolute;content:var(--tw-content);inset:calc(var(--spacing)*0)}
.c-radio__indicator:before{content:var(--tw-content);width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}
.c-radio:before{content:var(--tw-content);border-radius:3.40282e38px}
.c-radio__indicator:before{content:var(--tw-content);border-radius:3.40282e38px;content:var(--tw-content);background-color:var(--primary-foreground)}
.c-radio:not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{content:var(--tw-content);--tw-shadow:0 1px var(--tw-shadow-color,#0000000a)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{--tw-shadow:0 1px var(--tw-shadow-color,color-mix(in oklab,var(--color-black)4%,transparent))}
}
.c-radio:not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
.c-radio:has(>.c-radio__input:focus-visible){--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);--tw-ring-color:var(--ring);--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color);--tw-ring-offset-color:var(--background)}
.c-radio[aria-invalid=true]{border-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-radio[aria-invalid=true]{border-color:color-mix(in oklab,var(--destructive)36%,transparent)}
}
.c-radio:has(>.c-radio__input:focus-visible)[aria-invalid=true]{border-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:has(>.c-radio__input:focus-visible)[aria-invalid=true]{border-color:color-mix(in oklab,var(--destructive)64%,transparent)}
}
.c-radio:has(>.c-radio__input:focus-visible)[aria-invalid=true]{--tw-ring-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:has(>.c-radio__input:focus-visible)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)48%,transparent)}
}
.c-radio__input:checked~.c-radio__indicator{background-color:var(--primary)}
.c-radio:has(>.c-radio__input:disabled){cursor:not-allowed;opacity:.64}
.c-radio__input:not(:checked)~.c-radio__indicator{display:none}
@media (min-width:40rem){
.c-radio{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}
.c-radio__indicator{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}
.c-radio-group__legend{font-size:var(--text-sm);line-height:calc(var(--spacing)*4)}
.c-radio-label{font-size:var(--text-sm);line-height:calc(var(--spacing)*4)}
.c-radio__indicator:before{content:var(--tw-content);width:calc(var(--spacing)*1.5);height:calc(var(--spacing)*1.5)}
}
.c-radio:is(.dark *):not(:has(>.c-radio__input:checked)){background-color:var(--input)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:is(.dark *):not(:has(>.c-radio__input:checked)){background-color:color-mix(in oklab,var(--input)32%,transparent)}
}
.c-radio:is(.dark *):not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{content:var(--tw-content);--tw-shadow:0 -1px var(--tw-shadow-color,#ffffff0f)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:is(.dark *):not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{--tw-shadow:0 -1px var(--tw-shadow-color,color-mix(in oklab,var(--color-white)6%,transparent))}
}
.c-radio:is(.dark *):not(:has(>.c-radio__input:disabled)):not(:has(>.c-radio__input:checked)):not([aria-invalid=true]):before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
.c-radio:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-radio:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)24%,transparent)}
}
.c-radio:is(:has(>.c-radio__input:disabled),:has(>.c-radio__input:checked),:has(>.c-radio__input[aria-invalid=true])){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
/* propio */
.c-radio__input{position:absolute;inset:-1px;z-index:1;margin:0;opacity:0;cursor:pointer;appearance:none;border-radius:50%}
.c-radio__input:disabled{cursor:not-allowed}
.c-radio__indicator::before{content:""}
.c-radio-label{cursor:pointer}
.c-radio-label:has(:disabled){cursor:not-allowed;opacity:.64}
.c-radio-label--top{align-items:flex-start}
.c-radio-label--top .c-radio{margin-top:1px}
.c-radio-label__text{display:grid;gap:.25rem}
fieldset.c-radio-group{border:0;margin:0;padding:0;min-width:0}
.c-radio-group--row{flex-direction:row;flex-wrap:wrap;gap:1.25rem}
```

## Credits

- coss ui (MIT) · radio-group.tsx: https://coss.com/ui
- W3C WAI-ARIA APG, Radio Group: https://www.w3.org/WAI/ARIA/apg/patterns/radio/
