Radio Group
Single-select option group with arrow-key navigation and ARIA radiogroup semantics. Ideal for pricing tiers, settings panels, and any context where exactly one choice must be made from a visible set of options.
<arc-radio-group> Overview
Guidelines
When to use
- Use RadioGroup when users must choose exactly one option from two to six visible choices
- Default-select the most common or recommended option to reduce decision friction
- Use vertical orientation when option labels are longer than a few words
- Pair with a visible label or heading so users understand what they are choosing
- Group related radio groups under a shared fieldset or section heading
When not to use
- Do not use RadioGroup for more than six or seven options — switch to Select or Combobox instead
- Do not leave the group without a default selection unless the choice is truly optional
- Do not mix RadioGroup with checkboxes in the same visual row — they imply different selection models
- Do not use horizontal orientation with long labels — text will wrap awkwardly on small screens
- Do not disable individual options without explaining why they are unavailable
Features
- Single-select from a visible set of options — one choice at a time
- Arrow-key navigation with roving tabindex (single Tab stop)
- ARIA radiogroup role with automatic `aria-checked` management
- Vertical and horizontal orientation modes
- Disabled state for the entire group or individual options
- Native form integration via name and value properties
- Fires `arc-change` event on selection with the new value
- Supports rich option objects with label and value fields
Preview
Usage
Layout and styling work without JavaScript via the HTML/CSS versions. Interactive features like events and state management require the Web Component or a framework wrapper.
<script type="module" src="@arclux/arc-ui"></script>
<!-- Vertical (default) -->
<arc-radio-group name="plan" value="starter">
<arc-radio value="starter">Starter — Free for individuals</arc-radio>
<arc-radio value="pro">Pro — $12/mo for teams</arc-radio>
<arc-radio value="enterprise">Enterprise — Custom pricing</arc-radio>
</arc-radio-group>
<!-- Horizontal layout -->
<arc-radio-group name="size" value="md" orientation="horizontal">
<arc-radio value="sm">Small</arc-radio>
<arc-radio value="md">Medium</arc-radio>
<arc-radio value="lg">Large</arc-radio>
<arc-radio value="xl">X-Large</arc-radio>
</arc-radio-group>
<script>
document.querySelector('arc-radio-group')
.addEventListener('arc-change', (e) => {
console.log('Selected:', e.detail.value);
});
</script> import { RadioGroup, Radio } from '@arclux/arc-ui-react';
import { useState } from 'react';
function PricingPlan() {
const [plan, setPlan] = useState('starter');
return (
<RadioGroup
name="plan"
value={plan}
onArcChange={(e) => setPlan(e.detail.value)}
>
<Radio value="starter">Starter — Free for individuals</Radio>
<Radio value="pro">Pro — $12/mo for teams</Radio>
<Radio value="enterprise">Enterprise — Custom pricing</Radio>
</RadioGroup>
);
}
function SizeSelector() {
return (
<RadioGroup name="size" value="md" orientation="horizontal">
<Radio value="sm">Small</Radio>
<Radio value="md">Medium</Radio>
<Radio value="lg">Large</Radio>
<Radio value="xl">X-Large</Radio>
</RadioGroup>
);
} <script setup>
import { RadioGroup, Radio } from '@arclux/arc-ui-vue';
import { ref } from 'vue';
const plan = ref('starter');
</script>
<template>
<RadioGroup name="plan" :value="plan" @arc-change="plan = $event.detail.value">
<Radio value="starter">Starter — Free for individuals</Radio>
<Radio value="pro">Pro — $12/mo for teams</Radio>
<Radio value="enterprise">Enterprise — Custom pricing</Radio>
</RadioGroup>
</template> <script>
import { RadioGroup, Radio } from '@arclux/arc-ui-svelte';
let theme = 'dark';
</script>
<RadioGroup name="theme" value={theme} orientation="horizontal"
on:arc-change={(e) => theme = e.detail.value}>
<Radio value="light">Light</Radio>
<Radio value="dark">Dark</Radio>
<Radio value="auto">System</Radio>
</RadioGroup> import { Component } from '@angular/core';
import { RadioGroup, Radio } from '@arclux/arc-ui-angular';
@Component({
imports: [RadioGroup, Radio],
template: `
<arc-radio-group name="plan" [value]="plan" (arc-change)="plan = $event.detail.value">
<arc-radio value="starter">Starter — Free for individuals</arc-radio>
<arc-radio value="pro">Pro — $12/mo for teams</arc-radio>
<arc-radio value="enterprise">Enterprise — Custom pricing</arc-radio>
</arc-radio-group>
`,
})
export class PricingComponent {
plan = 'starter';
} import { RadioGroup, Radio } from '@arclux/arc-ui-solid';
import { createSignal } from 'solid-js';
function ShippingMethod() {
const [method, setMethod] = createSignal('standard');
return (
<RadioGroup name="shipping" value={method()}
onArcChange={(e) => setMethod(e.detail.value)}>
<Radio value="standard">Standard — 5-7 business days</Radio>
<Radio value="express">Express — 2-3 business days</Radio>
<Radio value="overnight">Overnight — Next business day</Radio>
</RadioGroup>
);
} import { RadioGroup, Radio } from '@arclux/arc-ui-preact';
import { useState } from 'preact/hooks';
function NotificationPreference() {
const [pref, setPref] = useState('email');
return (
<RadioGroup name="notify" value={pref}
onArcChange={(e) => setPref(e.detail.value)}>
<Radio value="email">Email notifications</Radio>
<Radio value="sms">SMS notifications</Radio>
<Radio value="push">Push notifications</Radio>
<Radio value="none">No notifications</Radio>
</RadioGroup>
);
} <!-- arc-radio-group is interactive — requires JS -->
<arc-radio-group></arc-radio-group> <!-- arc-radio-group is interactive — requires JS -->
<arc-radio-group></arc-radio-group> API
-
valuestring'' - The currently selected value. Must match one of the child arc-radio value attributes. Setting this property programmatically updates the visual selection and the internal aria-checked state.
-
namestring'' - The form field name submitted with the selected value. Required for native form integration — without it, the selection will not appear in FormData.
-
disabledbooleanfalse - When true, disables all options in the group. The component becomes non-interactive: arrow-key navigation is suppressed, click events are ignored, and the group is excluded from the Tab order.
-
size'sm' | 'md' | 'lg''md' - Controls the radio button and label size.
-
orientation'vertical' | 'horizontal''vertical' - Controls the layout direction of the radio options. Vertical stacks options top-to-bottom and maps Arrow Up/Down to navigation. Horizontal places options in a row and maps Arrow Left/Right.
-
formAssociatedbooleantrue -
propertiesobject{ required: { type: Boolean, reflect: true }, readonly: { type: Boolean, reflect: true }, } - Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. `required` participates in constraint validation below; `readonly` reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
-
autoValidatesbooleantrue - Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
-
form -
validity -
validationMessage -
requiredbooleanfalse -
readonlybooleanfalse
Events
-
arc-changedetail: { value: string } - Fired when the selected radio value changes
Radio
<arc-radio> Individual radio option rendered inside a RadioGroup. Each Radio represents a single selectable choice with its own label and value. Can be independently disabled while the rest of the group remains interactive.
-
label -
valuestring'' - The value submitted when this option is selected. Must be unique within the parent RadioGroup.
-
disabledbooleanfalse - When true, dims this individual option and removes it from keyboard navigation. The option cannot be selected by click or arrow keys.
See Also
- Select Dropdown select with searchable options, keyboard navigation, and full ARIA listbox semantics for accessible form inputs.
- Segmented Control A radio-group-style toggle bar that renders slotted arc-option elements as a row of mutually exclusive buttons with an active highlight.
- Checkbox Multi-select form control supporting checked, indeterminate, and disabled states. Ideal for preferences, bulk-selection patterns, and consent forms where users need to toggle one or more independent options.