Docs

Choice

A radio group for single_choice or a checkbox group for multiple_choice.

Options as a vertical list of bordered cards, each with a radio or checkbox that Mirio draws (.mirio-check), so it follows the theme in light and dark. Field renders it for single_choice (one value) and multiple_choice (an array).

Preview

Usage

// { key: 'timeline', type: 'single_choice', label: 'When do you want to start?', options: ['This month', 'This quarter', 'Just looking'], required: true }
import { Form } from '@trymirio/mirio';

<Form schema={demo} client={mirio} />

// by hand:
import { Choice } from '@trymirio/mirio';
<Choice name="timeline" optionClassName="py-2" />

Props

Prop Type Default Description
name string required The field key.
className string flex flex-col gap-2 Merged onto the group element.
optionClassName string option card classes Merged onto every option <label>.
…<div> attributes Spread on the group element (except onChange).

Rendered structure:

<div id="…" role="radiogroup|group" tabindex="-1" aria-labelledby="…-label" data-mirio="choice" [data-multiple]>
  <label for="…-0" data-mirio="option" [data-checked]>
    <input id="…-0" type="radio|checkbox" class="mirio-check" name="timeline" value="This month" />
    <span>This month</span>
  </label>
  …
</div>

The group element carries the field id, so error focus lands on it, and data-multiple is present for checkbox groups. multiple_choice honours minSelected/maxSelected on submit.

Variants and states

Checkbox group:

// { key: 'channels', type: 'multiple_choice', label: 'How did you hear about us?', help: 'Pick up to two.', options: ['Search', 'A friend', 'Social media', 'Newsletter'], maxSelected: 2 }
<Form schema={survey} client={mirio} />
  • Checked: the option card gets data-checked and a --mirio-ring border (has-[:checked]:border-mirio-ring).
  • Hover: cards tint with --mirio-muted.
  • Error: the group gets aria-invalid; the message renders below the group.
  • Prefill: defaultValue: 'This month' or, for multiple, defaultValue: ['Search'].

Customization

  • Tokens: --mirio-border, --mirio-bg, --mirio-muted (hover), --mirio-ring (checked border and focus ring), --mirio-input-bg and --mirio-border (the unchecked box), --mirio-primary and --mirio-primary-fg (the checked box and its check or dot), --mirio-radius.
  • Horizontal options: className="flex-row flex-wrap". Pills: optionClassName="rounded-full py-1.5".
  • CSS hooks: [data-mirio="choice"], [data-mirio="choice"][data-multiple], [data-mirio="option"][data-checked], and the box itself: .mirio-check, .mirio-check:checked, .mirio-check::before (the check or dot). The box is centered on the first line of its label.
  • The whole option card is the <label>, so clicking anywhere on it toggles the input.

Accessibility

role="radiogroup" (single) or role="group" (multiple) labelled by the field label through aria-labelledby; help and error through aria-describedby; each option is a real <input> with its own <label>, so arrow keys (radios) and Space work natively and screen readers announce "1 of 3".

Select, YesNo, Field, Schema: field types