Radio Group
The single-choice counterpart to Checkbox Group, with the same option-key API.
'use client'
import * as React from 'react'
import { Radio } from '@/components/custom/radio'
const LEAVE_TYPES = [
{ value: 'annual', label: 'Annual' },
{ value: 'sick', label: 'Sick' },
{ value: 'maternity', label: 'Maternity' },
{ value: 'paternity', label: 'Paternity' },
{ value: 'unpaid', label: 'Unpaid' },
]
export default function RadioDemo() {
const [type, setType] = React.useState('annual')
return (
<div className="w-full max-w-xl">
<Radio
label="Leave type"
required
data={LEAVE_TYPES}
value={type}
onChange={setType}
// Short list, so the filter would be noise.
searchPlaceholder=""
/>
</div>
)
}Installation
pnpm dlx shadcn@latest add https://kiotapay-ui-staging.staging.kiotapay.com/r/radio.jsonnpx shadcn@latest add https://kiotapay-ui-staging.staging.kiotapay.com/r/radio.jsonyarn dlx shadcn@latest add https://kiotapay-ui-staging.staging.kiotapay.com/r/radio.jsonbunx --bun shadcn@latest add https://kiotapay-ui-staging.staging.kiotapay.com/r/radio.jsonUsage
'use client'
import { Radio } from '@/components/custom/radio'
export function LeaveTypeField({ types, value, onChange }) {
return (
<Radio
label="Leave type"
required
data={types}
value={value}
onChange={onChange}
searchPlaceholder=""
/>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | FieldOption[] | [] | Options. Any object shape. |
value | unknown | — | Matched against option[valueKey]. |
onChange | (value: any) => void | — | Receives option[valueKey]. |
valueKey | string | 'value' | Property read for the stored value. |
labelKey | string | string[] | 'label' | Property or properties read for the label. |
label | string | — | Required. Labels the group. |
placeholder | string | 'Select an option...' | Shown when the list is empty or filtered to nothing. |
searchPlaceholder | string | 'Search...' | Pass '' to hide the filter entirely. |
disabled | boolean | false | Blocks every option. |
error | boolean | false | Switches the group border to the danger ramp. |
errorMessage | ReactNode | — | Shown only while error is true. |
Behaviour notes
The group name is generated, not the label. Radio inputs are grouped by their name attribute, so using the visible heading merges any two groups that happen to share one — selecting in the first silently clears the second. Each instance gets its own generated id instead.
Native inputs underneath. The visible circle is styling over a real <input type="radio">, so arrow-key navigation within the group works exactly as the platform defines it.
Hide the filter on short lists. Under about eight options it is noise; pass searchPlaceholder="".