Radio Group
Grouped selection primitive that coordinates ui-radio descendants, keyboard navigation, and normalized selection events.
Default horizontal
With orientation omitted, Radio Group lays out its options horizontally.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-radio-group/ui-radio-group.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-radio/ui-radio.html"
>
<ui-radio-group
label="Options"
name="radio-group-group"
>
<ui-radio
value="one"
>One</ui-radio>
<ui-radio
value="two"
>Two</ui-radio>
</ui-radio-group><script setup>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<template>
<UiRadioGroup
label="Options"
name="radio-group-group"
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
</UiRadioGroup>
</template>import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Options"
name="radio-group-group"
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
</UiRadioGroup>;
}/** @jsxImportSource preact */
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Options"
name="radio-group-group"
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
</UiRadioGroup>;
}<script>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<UiRadioGroup
label="Options"
name="radio-group-group"
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
</UiRadioGroup>import { Component } from "@angular/core";
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiRadioGroup, UiRadio],
template: `
<fieldset
ui-radio-group
[label]="'Options'"
[name]="'radio-group-group'"
>
<label
ui-radio
[value]="'one'"
>One</label>
<label
ui-radio
[value]="'two'"
>Two</label>
</fieldset>
`,
})
export default class Example {}Vertical, required, and value
Orientation changes the axis; required and value define group validation and selection.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-radio-group/ui-radio-group.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-radio/ui-radio.html"
>
<ui-radio-group
label="Priority"
value="two"
name="radio-group-vertical"
orientation="vertical"
required
>
<ui-radio
value="one"
>One</ui-radio>
<ui-radio
value="two"
>Two</ui-radio>
<ui-radio
value="three"
>Three</ui-radio>
</ui-radio-group><script setup>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<template>
<UiRadioGroup
label="Priority"
value="two"
name="radio-group-vertical"
orientation="vertical"
:required="true"
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
<UiRadio
value="three"
>Three</UiRadio>
</UiRadioGroup>
</template>import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Priority"
value="two"
name="radio-group-vertical"
orientation="vertical"
required
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
<UiRadio
value="three"
>Three</UiRadio>
</UiRadioGroup>;
}/** @jsxImportSource preact */
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Priority"
value="two"
name="radio-group-vertical"
orientation="vertical"
required
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
<UiRadio
value="three"
>Three</UiRadio>
</UiRadioGroup>;
}<script>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<UiRadioGroup
label="Priority"
value="two"
name="radio-group-vertical"
orientation="vertical"
required
>
<UiRadio
value="one"
>One</UiRadio>
<UiRadio
value="two"
>Two</UiRadio>
<UiRadio
value="three"
>Three</UiRadio>
</UiRadioGroup>import { Component } from "@angular/core";
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiRadioGroup, UiRadio],
template: `
<fieldset
ui-radio-group
[label]="'Priority'"
[value]="'two'"
[name]="'radio-group-vertical'"
[orientation]="'vertical'"
[required]="true"
>
<label
ui-radio
[value]="'one'"
>One</label>
<label
ui-radio
[value]="'two'"
>Two</label>
<label
ui-radio
[value]="'three'"
>Three</label>
</fieldset>
`,
})
export default class Example {}disabled
Disabled makes every radio in the group unavailable.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-radio-group/ui-radio-group.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-radio/ui-radio.html"
>
<ui-radio-group
label="Plan"
name="radio-group-disabled-plan"
value="free"
disabled
>
<ui-radio
value="free"
checked
>Free</ui-radio>
<ui-radio
value="pro"
>Pro</ui-radio>
</ui-radio-group><script setup>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<template>
<UiRadioGroup
label="Plan"
name="radio-group-disabled-plan"
value="free"
:disabled="true"
>
<UiRadio
value="free"
:checked="true"
>Free</UiRadio>
<UiRadio
value="pro"
>Pro</UiRadio>
</UiRadioGroup>
</template>import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Plan"
name="radio-group-disabled-plan"
value="free"
disabled
>
<UiRadio
value="free"
checked
>Free</UiRadio>
<UiRadio
value="pro"
>Pro</UiRadio>
</UiRadioGroup>;
}/** @jsxImportSource preact */
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
label="Plan"
name="radio-group-disabled-plan"
value="free"
disabled
>
<UiRadio
value="free"
checked
>Free</UiRadio>
<UiRadio
value="pro"
>Pro</UiRadio>
</UiRadioGroup>;
}<script>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<UiRadioGroup
label="Plan"
name="radio-group-disabled-plan"
value="free"
disabled
>
<UiRadio
value="free"
checked
>Free</UiRadio>
<UiRadio
value="pro"
>Pro</UiRadio>
</UiRadioGroup>import { Component } from "@angular/core";
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiRadioGroup, UiRadio],
template: `
<fieldset
ui-radio-group
[label]="'Plan'"
[name]="'radio-group-disabled-plan'"
[value]="'free'"
[disabled]="true"
>
<label
ui-radio
[value]="'free'"
[checked]="true"
>Free</label>
<label
ui-radio
[value]="'pro'"
>Pro</label>
</fieldset>
`,
})
export default class Example {}Invalid group
Invalid marks the whole group and its legend; a form can show a related validation message beside it.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-radio-group/ui-radio-group.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-radio/ui-radio.html"
>
<ui-radio-group
invalid
required
name="delivery"
label="Delivery method"
>
<ui-radio
value="ship"
>Ship</ui-radio>
<ui-radio
value="pickup"
>Pick up</ui-radio>
</ui-radio-group><script setup>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<template>
<UiRadioGroup
:invalid="true"
:required="true"
name="delivery"
label="Delivery method"
>
<UiRadio
value="ship"
>Ship</UiRadio>
<UiRadio
value="pickup"
>Pick up</UiRadio>
</UiRadioGroup>
</template>import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
invalid
required
name="delivery"
label="Delivery method"
>
<UiRadio
value="ship"
>Ship</UiRadio>
<UiRadio
value="pickup"
>Pick up</UiRadio>
</UiRadioGroup>;
}/** @jsxImportSource preact */
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
export default function Example() {
return <UiRadioGroup
invalid
required
name="delivery"
label="Delivery method"
>
<UiRadio
value="ship"
>Ship</UiRadio>
<UiRadio
value="pickup"
>Pick up</UiRadio>
</UiRadioGroup>;
}<script>
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
</script>
<UiRadioGroup
invalid
required
name="delivery"
label="Delivery method"
>
<UiRadio
value="ship"
>Ship</UiRadio>
<UiRadio
value="pickup"
>Pick up</UiRadio>
</UiRadioGroup>import { Component } from "@angular/core";
import { UiRadio, UiRadioGroup } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiRadioGroup, UiRadio],
template: `
<fieldset
ui-radio-group
[invalid]="true"
[required]="true"
[name]="'delivery'"
[label]="'Delivery method'"
>
<label
ui-radio
[value]="'ship'"
>Ship</label>
<label
ui-radio
[value]="'pickup'"
>Pick up</label>
</fieldset>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: fieldset
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
disabled | Disables every radio in the group through the native fieldset, so no choice can be made and the group submits nothing with its form. A radio disabled on its own stays disabled when the group is enabled. | disabled | boolean | false | — |
form | Associate the group’s native radios with this form ID. Omit it to use their containing form; an empty string leaves them outside form submission. | form | string | — | — |
invalid | Exposes an externally validated error on the group and styles its legend with the field danger colour. | invalid | boolean | false | — |
label | The group's legend, shown above the radios and announced as the group's name. Phrase it as the question the radios answer. | label | string | Options | — |
label-visibility | visible shows the legend; sr-only hides it visually but keeps it as the group's accessible name. Use sr-only only when the surrounding layout already makes the choice clear, as with a row of colour swatches. | labelVisibility | keyword | visible | visible, sr-only |
name | The native name given to every radio in the group, under which a form submits the chosen value. Left empty, the group generates a unique name that keeps the radios together, so set it when the choice submits with a form. | name | string | | — |
orientation | horizontal lays the radios out in a row; vertical stacks them in a column. The arrow keys move between radios either way. | orientation | keyword | horizontal | horizontal, vertical |
required | Makes a choice required, as a required native radio does for its group: the group states aria-required, every radio in it is marked required, and native form validation fails until one is checked. | required | boolean | false | — |
value | The value of the checked radio, initially or when set externally; empty checks none. The user's choice updates it from there and is reported as select and change events, and a form reset returns the group to it. | value | string | | — |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
disabled | boolean | false | — |
form | string | — | — |
invalid | boolean | false | — |
label | string | Options | — |
labelVisibility | "visible" | "sr-only" | visible | visible, sr-only |
name | string | | — |
orientation | "horizontal" | "vertical" | horizontal | horizontal, vertical |
required | boolean | false | — |
value | string | | — |
Events
| Name | Detail | Description |
|---|---|---|
change | object
| Emitted when a toggleable control changes checked state. |
select | object
| Emitted when a selectable option becomes active. |
Slots
| Name | Purpose |
|---|---|
default | Default child content. |
Design tokens
Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.
Component tokens
| Token | Declared values | Fallback |
|---|---|---|
--ui-radio-group-invalid-text | — | var(--ui-field-danger, var(--ui-danger-solid)) |
Shared tokens
| Token | Fallback |
|---|---|
--ui-danger-solid | — |
--ui-field-danger | var(--ui-danger-solid) |
--ui-font-medium | — |
--ui-space-2 | — |
--ui-text-primary | — |