Svelte Headless UI

Radio Group

Basic example

Radio Groups are built using a combination of the RadioGroup, RadioGroupOption, RadioGroupLabel, and RadioGroupDescription components:

<script>
  import {
    RadioGroup,
    RadioGroupLabel,
    RadioGroupOption,
    RadioGroupDescription,
  } from "@rgossiaux/svelte-headlessui";

  let plan = "startup";
</script>

<RadioGroup value={plan} on:change={(e) => (plan = e.detail)}>
  <RadioGroupLabel>Plan</RadioGroupLabel>
  <RadioGroupOption value="startup" let:checked>
    <span class:checked>Startup</span>
  </RadioGroupOption>
  <RadioGroupOption value="business" let:checked>
    <span class:checked>Business</span>
  </RadioGroupOption>
  <RadioGroupOption value="enterprise" let:checked>
    <span class:checked>Enterprise</span>
  </RadioGroupOption>
</RadioGroup>

<style>
  .checked {
    /* Your styles here */
  }
</style>

Styling

See here for some general notes on styling the components in this library.

Checked option

To style the selected RadioGroupOption, you can use the checked slot prop that it provides, which tells you whether or not that option is the currently selected one. You can use this state to conditionally apply whatever styles you wish.

<script>
  import {
    RadioGroup,
    RadioGroupLabel,
    RadioGroupOption,
  } from "@rgossiaux/svelte-headlessui";

  let plan = "startup";
</script>

<RadioGroup value={plan} on:change={(e) => (plan = e.detail)}>
  <RadioGroupLabel>Plan</RadioGroupLabel>
  <!-- Use the `checked` slot prop to conditionally style the checked item -->
  <RadioGroupOption value="startup" let:checked>
    <span class:checked>Startup</span>
  </RadioGroupOption>
  <!-- ... -->
</RadioGroup>

<style>
  .checked {
    /* Your styles here */
  }
</style>

Active options

RadioGroupOptions can also be in an active state if they are focused with either the mouse or the keyboard. It’s a good idea to add styles specifically for this state.

<script>
  import {
    RadioGroup,
    RadioGroupLabel,
    RadioGroupOption,
  } from "@rgossiaux/svelte-headlessui";

  let plan = "startup";
</script>

<RadioGroup value={plan} on:change={(e) => (plan = e.detail)}>
  <RadioGroupLabel>Plan</RadioGroupLabel>
  <!-- Use both `active` and `checked` slot props
        to differentiate between the active and checked states -->
  <RadioGroupOption value="startup" let:active let:checked>
    <span class:active class:checked>Startup</span>
  </RadioGroupOption>
  <!-- ... -->
</RadioGroup>

<style>
  .active {
    /* Your styles here */
  }

  .checked {
    /* Your styles here */
  }
</style>

Using the Label and Description components

You can use the RadioGroupLabel and RadioGroupDescription components to label and describe each RadioGroupOption, as well as the RadioGroup itself. These components will automatically link with their relevant ancestor components via the aria-labelledby and aria-describedby attributes, improving the semantics and accessibility of your component.

By default, RadioGroupLabel renders a <label> element and RadioGroupDescription renders a <p>. These can be customized using the as prop, as described in the API docs below.

<script>
  import {
    RadioGroup,
    RadioGroupLabel,
    RadioGroupOption,
    RadioGroupDescription,
  } from "@rgossiaux/svelte-headlessui";

  let plan = "startup";
</script>

<RadioGroup value={plan} on:change={(e) => plan = e.detail}>
  <!-- This Label is for the `RadioGroup` -->
  <RadioGroupLabel>Plan</RadioGroupLabel>

  <RadioGroupOption value="startup" let:checked>
    <RadioGroupLabel as="span" class:checked>Startup</span>
    <RadioGroupDescription as="span" class:checked>
      Up to 5 active job postings
    </RadioGroupDescription>
  </RadioGroupOption>
  <!-- ... -->
</RadioGroup>

<style>
  /* WARNING: This is just for demonstration.
      Using :global() in this way can be risky. */
  :global(.checked) {
    /* Your styles here */
  }
</style>

Using with HTML forms

If you add the name prop to your listbox, hidden input elements will be rendered and kept in sync with your selected value.

<script>
  import {
    RadioGroup,
    RadioGroupLabel,
    RadioGroupOption,
    RadioGroupDescription,
  } from "@rgossiaux/svelte-headlessui";

  const plans = ['startup', 'business', 'enterprise']

  let selectedPlan = plans[0];
</script>

<RadioGroup value={selectedPlan} on:change={(e) => (selectedPlan = e.detail)} name="plan">
  <RadioGroupLabel>Plan</RadioGroupLabel>
  {#each plans as plan}
    <RadioGroupOption value={plan} let:checked>
      <span>{plan}</span>
    </RadioGroupOption>
  {/each}  
</RadioGroup>

This lets you use a radio group inside a native HTML <form> and make traditional form submissions as if your radio group was a native HTML form control.

Basic values like strings will be rendered as a single hidden input containing that value, but complex values like objects will be encoded into multiple inputs using a square bracket notation for the names.

<input type="hidden" name="plan" value="startup" />

Accessibility notes

Mouse interaction

Clicking a RadioGroupOption will select it.

Keyboard interaction

Command Description
<ArrowDown> / <ArrowRight> when RadioGroup is focused Focuses and checks the next RadioGroupOption
<ArrowUp> / <ArrowLeft> when RadioGroup is focused Focuses and checks the previous RadioGroupOption
<Space> when RadioGroup is focused Checks the current RadioGroupOption if it is not already checked

Other

All relevant ARIA attributes are automatically managed.

For a full reference on all accessibility features implemented in RadioGroup, see the ARIA spec on Radio Groups.

Component API

RadioGroup

The main Radio Group component.

Prop Default Type Description
as div string The element the RadioGroup should render as
disabled false boolean Whether the RadioGroup and all of its RadioGroupOptions are disabled
value β€” T | undefined The currently selected value in the RadioGroup
name β€” string The name used when using this component inside a form.

This component also dispatches a custom event, which is listened to using the Svelte on: directive:

Event name Type of event .detail Description
change T Dispatched when a RadioGroupOption is selected; the event detail contains the value of the selected option

RadioGroupOption

The wrapper component for each selectable option.

Prop Default Type Description
as div string The element the RadioGroupOption should render as
disabled false boolean Whether the RadioGroupOption is disabled
value β€” T | undefined The value of the RadioGroupOption; the type should match the type of the value prop in the RadioGroup
Slot prop Type Description
active boolean Whether the option is active (using the mouse or keyboard)
checked boolean Whether the option is the checked option
disabled boolean Whether the option is disabled

RadioGroupLabel

Renders an element that is linked to its nearest RadioGroup or RadioGroupOption ancestor component via the aria-labelledby attribute and an autogenerated id.

Prop Default Type Description
as label string The element the RadioGroupLabel should render as

If the RadioGroupLabel is labeling a RadioGroupOption (instead of the RadioGroup), it will also have these slot props available:

Slot prop Type Description
active boolean Whether the corresponding option is active (using the mouse or keyboard)
checked boolean Whether the corresponding option is the checked option
disabled boolean Whether the corresponding option is disabled

RadioGroupDescription

Renders an element that is linked to its nearest RadioGroup or RadioGroupOption ancestor component via the aria-describedby attribute and an autogenerated id.

Prop Default Type Description
as a string The element the RadioGroupDescription should render as

If the RadioGroupDescription is describing a RadioGroupOption (instead of the RadioGroup), it will also have these slot props available:

Slot prop Type Description
active boolean Whether the corresponding option is active (using the mouse or keyboard)
checked boolean Whether the corresponding option is the checked option
disabled boolean Whether the corresponding option is disabled