RadioGroup
Pick one option from a set — native radios, arrow-key navigation and a card style.
'use client';
import { Radio, RadioGroup } from '@akhatmirzo/ui';
export default function RadioGroupBasic() {
return (
<RadioGroup aria-label="To'lov usuli" defaultValue="click">
<Radio value="click" label="Click" />
<Radio value="payme" label="Payme" />
<Radio value="cash" label="Naqd pul" />
</RadioGroup>
);
}
Import
import { Radio, RadioGroup } from '@akhatmirzo/ui';When to use
- To pick one of 2–5 options — payment method, delivery type, plan. Every option stays visible, which makes comparing easy.
- With many options (more than 6), a
SelectorComboboxsaves space. - If several can be picked, use
Checkbox. - When options need a price or a note, use
variant="card": each option becomes a large clickable card. - Give the group a name — via the
Fieldlabeloraria-label.
Orientation
orientation="vertical" (default) stacks options. horizontal puts them in a row and wraps when
space runs out. Best for short labels.
'use client';
import { Radio, RadioGroup } from '@akhatmirzo/ui';
export default function RadioGroupHorizontal() {
return (
<RadioGroup aria-label="Yetkazib berish" orientation="horizontal" defaultValue="express">
<Radio value="express" label="Tezkor" />
<Radio value="standard" label="Oddiy" />
<Radio value="pickup" label="Olib ketish" />
</RadioGroup>
);
}
Sizes
Set size on the group and every radio follows: sm is 16px, md (default) is 20px.
'use client';
import { Radio, RadioGroup } from '@akhatmirzo/ui';
export default function RadioGroupSizes() {
return (
<div className="flex flex-wrap items-start gap-10">
<RadioGroup aria-label="Interfeys tili (kichik)" size="sm" defaultValue="uz">
<Radio value="uz" label="O'zbekcha" />
<Radio value="ru" label="Ruscha" description="Kirill yozuvida" />
</RadioGroup>
<RadioGroup aria-label="Interfeys tili (o'rta)" defaultValue="uz">
<Radio value="uz" label="O'zbekcha" />
<Radio value="ru" label="Ruscha" description="Kirill yozuvida" />
</RadioGroup>
</div>
);
}
Card variant
With variant="card", each Radio becomes a bordered card that is highlighted in primary when
selected. Great for prices, plans and payment methods: the label and description get plenty of
room.
Tanlangan tarif: pro
'use client';
import { Radio, RadioGroup } from '@akhatmirzo/ui';
import { useState } from 'react';
export default function RadioGroupCard() {
const [plan, setPlan] = useState('pro');
return (
<div className="flex w-full max-w-md flex-col gap-3">
<RadioGroup aria-label="Tarif" variant="card" value={plan} onValueChange={setPlan}>
<Radio value="free" label="Bepul" description="1 ta do'kon, asosiy imkoniyatlar" />
<Radio
value="pro"
label="Pro · 149 000 so'm"
description="Cheksiz do'konlar va hisobotlar"
/>
<Radio value="team" label="Jamoa" description="Tez orada" disabled />
</RadioGroup>
<p className="text-sm text-text-muted">Tanlangan tarif: {plan}</p>
</div>
);
}
States
Put disabled on the whole group or on a single Radio. invalid turns the circles' borders red
and sets aria-invalid on the group and radios.
'use client';
import { Radio, RadioGroup } from '@akhatmirzo/ui';
export default function RadioGroupStates() {
return (
<div className="flex flex-wrap items-start gap-10">
<RadioGroup aria-label="Butun guruh o'chirilgan" disabled defaultValue="a">
<Radio value="a" label="Tanlangan" />
<Radio value="b" label="Tanlanmagan" />
</RadioGroup>
<RadioGroup aria-label="Bitta variant o'chirilgan">
<Radio value="a" label="Omborda bor" />
<Radio value="b" label="Tugagan" disabled />
</RadioGroup>
<RadioGroup aria-label="Xato holati" invalid>
<Radio value="yes" label="Ha" />
<Radio value="no" label="Yo'q" />
</RadioGroup>
</div>
);
}
With Field
Inside a Field, the group is linked to the label with aria-labelledby, the hint and error go
into aria-describedby, and required, disabled and the error state pass down to the radios.
Usulni tanlang
'use client';
import { Field, Radio, RadioGroup } from '@akhatmirzo/ui';
import { useState } from 'react';
export default function RadioGroupWithField() {
const [value, setValue] = useState<string>();
return (
<Field label="Yetkazib berish" required error={value ? undefined : 'Usulni tanlang'}>
<RadioGroup value={value} onValueChange={setValue}>
<Radio value="courier" label="Kuryer" description="Ertaga, 25 000 so'm" />
<Radio value="pickup" label="Olib ketish" description="Bugun, bepul" />
</RadioGroup>
</Field>
);
}
Props
RadioGroup
RadioGroup accepts every other <div> attribute (aria-label, className ...).
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value |
defaultValue | string | — | Initial value (uncontrolled) |
onValueChange | (value: string) => void | — | Called when another option is selected |
orientation | 'vertical' | 'horizontal' | 'vertical' | Layout and aria-orientation |
variant | 'default' | 'card' | 'default' | card turns each option into a clickable card |
size | 'sm' | 'md' | 'md' | Circle size: 16 / 20px |
name | string | — | Shared name for the native radios (generated if omitted) |
disabled | boolean | — | Disables the whole group |
required | boolean | — | A choice is required |
invalid | boolean | — | Error state (automatic inside a Field with an error) |
Radio
Radio accepts the remaining <input> attributes; ref points to the inner <input> and
className goes to the root <label>. It only works inside a RadioGroup.
| Prop | Type | Default | Description |
|---|---|---|---|
valuerequired | string | — | Option value |
label | ReactNode | — | Text next to the circle |
description | ReactNode | — | Hint under the label |
disabled | boolean | — | Disables just this option |
className | string | — | Class for the root <label> |
Data attributes
| Element | Attributes |
|---|---|
RadioGroup | data-orientation, data-variant, data-size, data-invalid, data-disabled |
Radio | data-state (checked · unchecked), data-disabled |
Accessibility
- Native radios sharing one
name, so keyboard behavior comes from the browser:Tabmoves into and out of the group,↑↓/←→move between options and select them. role="radiogroup"witharia-orientation; inside aField, the name comes from the label viaaria-labelledby.- States are exposed on the group with
aria-required,aria-disabledandaria-invalid. - Descriptions are linked to each radio with
aria-describedby. - In the card variant, the focus ring wraps the whole card.