Skip to content

Radio Group

Group of checkable buttons that only allow one to be checked at a time.

Controls

Features

  • Full keyboard navigation.
  • Adds input elements to support forms.
  • Supports animating indicators.
  • Supports horizontal/vertical orientation.

Usage

Importing Radio gives you access to the Group and Button components.

MyComponent.svelte
<script lang="ts">
import { Radio } from "@niklasburggraaff/svelte-runia";
</script>
<Radio.Group aria-label="...">
<Radio.Button value="..." aria-label="...">
{#snippet indicator()}
...
{/snippet}
</Radio.Button>
</Radio.Group>
  • The Group can contain multiple Item’s and must be passed a aria-label, or aria-labelledby prop
  • Each Item must be passed a unique value prop and a labelledByContent, aria-label, or aria-labelledby prop
  • Each Item can be passed a indicator snippet
    • The indicator snippet is rendered when the Item is checked.

API

Group

div

The Group component contains the radio buttons. It manages the state of the radio group.

Props

  • name:string
    • The name of the radio group. Used as the name for the value in a form.
  • value:string | null = null (bindable)
    • The value of the checked item, null if no item is checked.
  • aria-label:string (2)
    • Description of what the group is a selection for.
  • aria-labelledby:string (1)
    • ID of element that describes what the group is a selection for.
  • required:boolean = false
    • When true, indicates a radio button must be checked.
  • disabled:boolean = false
    • When true, prevents the user from interacting with the radio group.
  • loop:boolean = true
    • When true, keyboard navigation will loop focus from the last to the first Item and vice versa.
  • orientation:"vertical" | "horizontal" | undefined = undefined
    • The orientation of the radio group, which determines which arrow keys are used for keyboard navigation.
  • direction:"ltr" | rtl" = "ltr"
    • The reading direction of the radio group, used to correct keyboard navigation.
  • element:HTMLDivElement (bindable)
    • The rendered div element.
PropTypeDefaultDescription
name
string -The name of the radio group. Used as the name for the value in a form.
value
string | null

(bindable)

null The value of the checked item, null if no item is checked.
aria-label (1)
string -Description of what the group is a selection for.
aria-labelledby (1)
string -ID of element that describes what the group is a selection for.
required
boolean false When true, indicates a radio button must be checked.
disabled
boolean false When true, prevents the user from interacting with the radio group.
loop
boolean true When true, keyboard navigation will loop focus from the last to the first Item and vice versa.
orientation
"vertical" | "horizontal" | undefined undefined The orientation of the radio group, which determines which arrow keys are used for keyboard navigation.
direction
"ltr" | rtl" 'ltr' The reading direction of the radio group, used to correct keyboard navigation.
element
HTMLDivElement

(bindable)

-The rendered div element.

(1)- One of aria-label aria-labelledby is required.

Data attributes

  • data-disabled
    • Present when the accordion is disabled.
  • data-orientation: "vertical" | "horizontal"
    • The orientation of the accordion. Not present when orientation = undefined.
AttributeValuesDescription
[data-disabled] -Present when the accordion is disabled.
[data-orientation] "vertical" | "horizontal" The orientation of the accordion. Not present when orientation = undefined.

Button

button

The Button component is an item that can be checked.

Then the indicator snippet is rendered inside the button when it is checked. The rendered button and indicator can be fully styled.

The Button component also renders a hidden input element with type="radio". This is to make the component work in forms.

The following is a pseudocode representing the implementation of the Button component.

RadioGroupButton.svelte
<script lang="ts">
let checked = $...;
</script>
<button>
{#if expanded}
{@render indicator(checked)}
{/if}
</button>
<input type="radio" aria-hidden={true} style={"opacity: 0"} />

Props

  • value:string *(bindable)
    • The value used to identify the item.
  • indicator:Snippet<[boolean]>
    • When true, the item is a section element. Avoid using with many (~6) items to prevent landmark region proliferation. This is especially helpful when content contain headings or a nested accordion.
  • labelledByContent:true (2)
    • Indicates the button contains text describing what the button is an option for.
  • aria-label:string (1)
    • Description of what the button is an option for.
  • aria-labelledby:string (1)
    • ID of element that describes what the button is an option for.
  • disabled:boolean = false
    • When true, prevents the user from interacting with the item.
  • element:HTMLDivElement | HTMLElement (bindable)
    • The rendered div or section element.
PropTypeDefaultDescription
value *
string

(bindable)

-The value used to identify the item.
indicator
Snippet<[boolean]> -When true, the item is a section element. Avoid using with many (~6) items to prevent landmark region proliferation. This is especially helpful when content contain headings or a nested accordion.
labelledByContent (1)
true -Indicates the button contains text describing what the button is an option for.
aria-label (1)
string -Description of what the button is an option for.
aria-labelledby (1)
string -ID of element that describes what the button is an option for.
disabled
boolean false When true, prevents the user from interacting with the item.
element
HTMLDivElement | HTMLElement

(bindable)

-The rendered div or section element.

(1)- One of labelledByContent aria-label aria-labelledby is required.

Data attributes

  • data-state: "checked" | "unchecked"
    • The state of the radio button. "checked" when the item is checked and "unchecked" when the item is not checked.
  • data-disabled
    • Present when the radio button is disabled. This can be due to the whole radio group or the item being disabled.
  • data-orientation: "vertical" | "horizontal"
    • The orientation of the radio group. Not present when orientation = undefined.
  • data-svelte-runia-radio-button
    • Present on all Button's. Used by Group to find them.
  • data-svelte-runia-value: string
    • The value identifying the item.
AttributeValuesDescription
[data-state] "checked" | "unchecked" The state of the radio button. "checked" when the item is checked and "unchecked" when the item is not checked.
[data-disabled] -Present when the radio button is disabled. This can be due to the whole radio group or the item being disabled.
[data-orientation] "vertical" | "horizontal" The orientation of the radio group. Not present when orientation = undefined.
[data-svelte-runia-radio-button]
-Present on all Button's. Used by Group to find them.
[data-svelte-runia-value]
string The value identifying the item.

Accessibility

Adheres to the WAI-ARIA Radio Group Pattern.

Keyboard interactions

  • Enter/Space :

    Attempts to select the item.

  • Tab/ShiftTab :

    Move focus to the next/previous focussable element.

  • Arrow Down/Arrow Up :

    Move focus to the next/previous Button. If loop = true, loops focus from the last to the first Button and vice versa.

  • Arrow Right/Arrow Left :

    Move focus to the Button to the right/left (depending on direction). If loop = true, loops focus from the last to the first Button and vice versa.

KeysConditionAction
Enter / SpaceIf focus on a ButtonAttempts to select the item.
Tab / ShiftTab-Move focus to the next/previous focussable element.
Arrow Down / Arrow UpIf focus on a Button (and orientation = undefined or orientation = "vertical")Move focus to the next/previous Button. If loop = true, loops focus from the last to the first Button and vice versa.
Arrow Right / Arrow LeftIf focus on a Button (and orientation = undefined or orientation = "horizontal")Move focus to the Button to the right/left (depending on direction). If loop = true, loops focus from the last to the first Button and vice versa.

Other events

  • Button. onclick :

    Attempts to select the item.

ComponentEventAction
ButtononclickAttempts to select the item.

ARIA attributes

Group

  • role: string
    • Set to radiogroup.
  • aria-required: boolean
    • Set based on the required prop.
AttributeTypeDescription
role string Set to radiogroup.
aria-required boolean Set based on the required prop.

Button

  • role: string
    • Set to radio.
  • aria-checked: "true" | "false"
    • "true" when the item is checked.
  • aria-label: string
    • Description of what the group is a selection for.
  • aria-labelledby: string
    • ID of element that describes what the group is a selection for.
AttributeTypeDescription
role string Set to radio.
aria-checked "true" | "false" "true" when the item is checked.
aria-label string Description of what the group is a selection for.
aria-labelledby string ID of element that describes what the group is a selection for.
Button input element
  • aria-hidden: boolean
    • Set to true when the input element is hidden.
  • aria-label: string
    • Description of what the button is an option for.
  • aria-labelledby: string
    • ID of element that describes what the button is an option for.
AttributeTypeDescription
aria-hidden boolean Set to true when the input element is hidden.
aria-label string Description of what the button is an option for.
aria-labelledby string ID of element that describes what the button is an option for.

Examples

Check item by default

Use the value prop to set the initial item to be checked.

<Radio.Group value="state">
<Radio.Button value="state">...</Radio.Button>
<Radio.Button value="derived">...</Radio.Button>
<Radio.Button value="effect">...</Radio.Button>
<Radio.Button value="props">...</Radio.Button>
</Radio.Group>

Control the checked item

Bind the value prop of the Root component to a variable to control the checked item. This allows both reading and writing the value of the checked item.

MyComponent.svelte
<script>
import { Radio } from "@niklasburggraaff/svelte-runia";
let value = $state(null);
</script>
<input bind:value />
<Radio.Group bind:value>
<Radio.Button value="state">...</Radio.Button>
<Radio.Button value="derived">...</Radio.Button>
<Radio.Button value="effect">...</Radio.Button>
<Radio.Button value="props">...</Radio.Button>
</Radio.Group>

Add label

Set the aria-label prop to the description of what the toggle does when pressed.

<Radio.Group aria-label="Select rune">
<Radio.Button aria-label="state" value="state">
...
</Radio.Button>
<Radio.Button aria-label="derived" value="derived">
...
</Radio.Button>
<Radio.Button aria-label="effect" value="effect">
...
</Radio.Button>
<Radio.Button aria-label="props" value="props">
...
</Radio.Button>
</Radio.Group>

Label by element

Set the aria-labelledby prop to the id of an element that describes what the toggle does when pressed. This is useful when using label elements especially as interactions are passed to the Button. Remember to set the for prop of the input to the id of the Radio.Button.

<Radio.Group id="select-rune" aria-labelledby="select-rune-label">
<label id="select-rune-label" for="select-rune">
Select rune:
</label>
<Radio.Button aria-labelledby="state-label" id="state" value="state">
...
</Radio.Button>
<label id="state-label" for="state" class="text-md">
State
</label>
<Radio.Button aria-labelledby="derived-label" id="derived" value="derived">
...
</Radio.Button>
<label id="derived-label" for="derived" class="text-md">
Derived
</label>
<Radio.Button aria-labelledby="effect-label" id="effect" value="effect">
...
</Radio.Button>
<label id="effect-label" for="effect" class="text-md">
Effect
</label>
<Radio.Button aria-labelledby="props-label" id="props" value="props">
...
</Radio.Button>
<label id="props-label" for="props" class="text-md">
Props
</label>
</Radio.Group>

Label by content

Set the labelledByContent prop to true to indicate the toggle contains text describing what the toggle does when pressed.

<Radio.Group aria-label="Select rune">
<Radio.Button labelledByContent value="state">
Select ...
</Radio.Button>
<Radio.Button labelledByContent value="derived">
Select ...
</Radio.Button>
<Radio.Button labelledByContent value="effect">
Select ...
</Radio.Button>
<Radio.Button labelledByContent value="props">
Select ...
</Radio.Button>
</Radio.Group>