# Radio

> Radio buttons for one choice among several. A CSS component with two classes and no JavaScript.

Plain CSS on an ordinary `<input type="radio">`. The buttons in a group are tied together by `name`, and that is what lets only one be selected, and lets the arrow keys move between them.

If the user can choose several, use [Checkbox](/components/checkbox.md). If there are many options, [Select](/components/select.md) takes less room on the screen.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/radio/radio.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/fieldset/fieldset.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/label/label.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<fieldset class="lt-fieldset">
<legend class="lt-legend" data-required="symbol">How do you want to receive the answer?</legend>


<div class="lt-radio-row">
  <input class="lt-radio" type="radio" id="reply-digital" name="reply" value="digital" checked />
  <label class="lt-label" for="reply-digital">In your digital mailbox</label>
</div>


<div class="lt-radio-row">
  <input class="lt-radio" type="radio" id="reply-post" name="reply" value="post" />
  <label class="lt-label" for="reply-post">As a letter in the post</label>
</div>


<div class="lt-radio-row">
  <input class="lt-radio" type="radio" id="reply-collect" name="reply" value="collect" disabled />
  <label class="lt-label" for="reply-collect">Collect at the office</label>
</div>
</fieldset>
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/radio.css"
import "@lo-tek/interfaces/fieldset.css"
import "@lo-tek/interfaces/label.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<div className={lt.radio.row}>
  <input {...lt.radio()} id="reply-digital" name="reply" value="digital" />
  <label {...lt.label()} htmlFor="reply-digital">Digitally</label>
</div>
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If the element is already there,** set them on it. That is the way when you enhance HTML a server or a template has sent:

```ts
import { lt } from "@lo-tek/interfaces"


const buttons = document.querySelectorAll<HTMLInputElement>("[name='reply']")


function mark(invalid: boolean) {
  for (const button of buttons) {
    lt.setAttributes(button, lt.radio({ state: invalid ? "invalid" : "default" }))
  }
}
```

You set `name` yourself, since only you know what the group is called. `lt.radio.row` gives the class for the row around it. See [Type-safe use](/type-safe-use.md).

The group always belongs in a [Fieldset](/components/fieldset.md). Without it only the option is read out, not the question it answers.

## States

**Plain HTML**

```html
<div class="lt-radio-row">
<input class="lt-radio" type="radio" id="invalid-choice" name="example" data-state="invalid" aria-invalid="true" />
<label class="lt-label" for="invalid-choice">You have to choose one option</label>
</div>
```

| `data-state` | Used for |
| - | - |
| *(omitted)* | Normal state |
| `invalid` | Validation has failed |
| `success` | The choice is confirmed valid. Use sparingly. |

If validation fails, set the state on every button in the group. It is the group that is invalid, not one of the buttons.

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-radio` | The button itself |
| `.lt-radio-row` | The row that holds the button and the text side by side |

| Variable | Default |
| - | - |
| `--lt-radio-size` | `var(--lt-spacing-5)` |

The dot is a gradient drawn in `--lt-color-accent-content`, so it follows the theme without a separate image. See [Customising](/customising.md).

## Accessibility

- Every button in the group has to share `name`. Without it each button becomes its own group, and the user can choose several.
- The arrow keys move between the buttons and select at the same time. Tab leaves the whole group. That is the browser’s own behaviour, and it should not be overridden.
- Do not preselect an option when the choice has a consequence. The default then becomes an answer the user never considered.
- If you only have two options that are each other’s opposite, consider [Checkbox](/components/checkbox.md) or [Switch](/components/switch.md) instead.
