RadioGroup
Pick exactly one from a short list where every option is on show.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { RadioGroup } from '@weft-js/warp'export function Window() { const when = state<'now' | 'night' | 'weekend'>('now') return <RadioGroup label="Maintenance window" value={when.value} options={[...WINDOWS]} onChange={v => (when.value = v)} />}const WINDOWS = [ { value: 'now', label: 'Right away', hint: 'Starts within a minute.' }, { value: 'night', label: 'Tonight', hint: 'At 02:00 in the project\'s region.' }, { value: 'weekend', label: 'This weekend', hint: 'Saturday at 02:00.', disabled: true },] as constInstallation
npm install @weft-js/warpUsage
tsx
import { RadioGroup } from '@weft-js/warp'Labels only
Leave out hint when the label says enough.
tsx
import { state } from '@weft-js/core'import { RadioGroup } from '@weft-js/warp'export function Plain() { const branch = state('main') return <RadioGroup label="Deploy from" value={branch.value} options={[{ value: 'main', label: 'main' }, { value: 'release', label: 'release' }, { value: 'tags', label: 'Tagged commits only' }]} onChange={v => (branch.value = v)} />}More than words
A label can be any content, like a badge with each region's latency.
tsx
import { state } from '@weft-js/core'import { Badge, RadioGroup, Row } from '@weft-js/warp'export function Rich() { const region = state('eu-west') return <RadioGroup label="Region" value={region.value} options={NEAR} onChange={v => (region.value = v)} />}const LATENCY = { 'eu-west': 18, 'us-east': 94, 'ap-south': 162 } as Record<string, number>const NEAR = Object.keys(LATENCY).map(r => ({ value: r, label: <Row gap="related">{r}<Badge tone={LATENCY[r]! < 50 ? 'positive' : LATENCY[r]! < 120 ? 'caution' : 'critical'}>{LATENCY[r]} ms</Badge></Row>, hint: r === 'eu-west' ? 'Closest to you.' : undefined,}))Choose a plan
Plan and seats both change the total.
tsx
import { state } from '@weft-js/core'import { RadioGroup, Row, Slider, Stack, Text } from '@weft-js/warp'export function Plan() { const plan = state('team') const seats = state(8) return ( <Stack gap="group"> <RadioGroup label="Plan" value={plan.value} options={PLANS} onChange={v => (plan.value = v)} /> <Slider label="Seats" value={seats.value} min={1} max={40} onChange={v => (seats.value = v)} /> <Row justify="between"> <Text subtle>Per month</Text> <Text role="heading">€{SEAT[plan.value]! * seats.value}</Text> </Row> </Stack> )}const min = 60_000const PLANS = [ { value: 'hobby', label: 'Hobby', hint: 'One project, free.' }, { value: 'team', label: 'Team', hint: '€20 a seat, unlimited projects.' }, { value: 'scale', label: 'Scale', hint: '€60 a seat, plus private regions.' },]const SEAT = { hobby: 0, team: 20, scale: 60 } as Record<string, number>In a form
name is what the choice posts under. Save reads it back from the form's data.
tsx
import { state } from '@weft-js/core'import { Button, RadioGroup, Row, Stack, Text } from '@weft-js/warp'export function Form() { const digest = state('daily') const sent = state('') const save = (e: Event) => { e.preventDefault() sent.value = `digest=${(new FormData(e.currentTarget as HTMLFormElement).get('digest') as string | null) ?? ''}` } return ( <Stack as="form" gap="group" onSubmit={save}> <Text role="heading">Failure emails</Text> <RadioGroup label="Failure emails" name="digest" value={digest.value} options={DIGESTS} onChange={v => (digest.value = v)} /> <Row justify="between"> <Text subtle role="caption">{sent.value ? `Posted ${sent.value}` : 'Nothing saved yet'}</Text> <Button type="submit">Save</Button> </Row> </Stack> )}const DIGESTS = [ { value: 'instant', label: 'As it happens', hint: 'One email for each failed deploy.' }, { value: 'daily', label: 'Daily digest', hint: 'At 08:00, if anything failed.' }, { value: 'off', label: 'Off', hint: 'Check the dashboard yourself.' },]When to use
Accessibility
- ↑↓
- Moves to the next choice and picks it
- Tab
- Moves in and out of the group
labelnames the group for screen readers, but isn't drawn. Put a heading above it when people need one too.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The group's accessible name. |
value | V | — | The value that is picked. |
options | RadioOption<V>[] | — | The choices: { value, label, hint, disabled }. |
name | string | — | The form field name. Made up for you when left out. |
| Event | Type | Default | Description |
|---|---|---|---|
onChange | (v: V) => void | — | Called with the new value. |