Radio
Basic Usage
The Radio field renders a group of radio buttons for selecting a single value.
Radio::make('digest_cadence')->options([
'daily' => 'Daily',
'weekly' => 'Weekly',
'monthly' => 'Monthly',
])->default('weekly');The default is null until a model or default() supplies a selection. Option values may be strings, numbers, booleans, or null; selected values are compared with strict equality.
Validation
With options, Radio automatically adds Rule::in(...) using the normalized option values. required() adds Laravel's required rule. It also exposes aria-required on the radiogroup and places the native required attribute on the first enabled option, which gives the browser one valid representative for the group without making a disabled option responsible for validation.
Options with Descriptions and Icons
Each option may include a description and resolver-backed icon name:
Radio::make('workflow_status')->options([
[
'value' => 'draft',
'label' => 'Draft',
'description' => 'Keep changes internal until they are ready.',
'icon' => 'SquarePenIcon',
],
[
'value' => 'review',
'label' => 'In review',
'description' => 'Ask reviewers to approve the next update.',
'icon' => 'ClipboardCheckIcon',
],
[
'value' => 'archived',
'label' => 'Archived',
'description' => 'Locked for historical reference.',
'icon' => 'ArchiveIcon',
'disabled' => true,
],
])->cards()->columns(2)->default('review');For options from arrays, Collections, models, or queries, choose the secondary line with optionDescription():
Radio::make('plan_id')
->options(Plan::query()->orderBy('name'), 'name', 'id')
->optionDescription('tagline');Use mapDescriptionAs() when the text needs custom PHP logic:
Radio::make('plan_id')
->options(Plan::query()->orderBy('name'), 'name', 'id')
->mapDescriptionAs(fn (Plan $plan) => "{$plan->seats} seats included");For simple translations, the shared option mappers also accept arrays:
Radio::make('plan')
->options(Plan::class, 'tier', 'id', 'billing_period')
->mapAs([
'starter' => 'Starter',
'team' => 'Team',
])
->mapDescriptionAs([
'monthly' => 'Billed monthly',
'yearly' => 'Billed yearly',
]);Option icons are resolver-backed icon names. See Icons.
Radio intentionally supports a narrower option metadata contract than custom Combobox: description, icon, and disabled. Use Combobox when options need images, avatars, disabled reasons, selected suffixes, server-side search, or custom Vue option slots.
Option Sources and Mapping
options() accepts an array, Collection, Arrayable object, Eloquent model class, Eloquent or query builder, or a closure that returns one of those sources. Finite model and query sources are resolved on the server before the field is serialized.
Associative scalar arrays use each array key as the value and each item as the label. Object and array records use value and label by default. Pass label, value, and description keys as the second through fourth options() arguments, or configure them separately:
Radio::make('plan_id')
->options(Plan::query()->orderBy('name'))
->optionLabel('name')
->optionValue('id')
->optionDescription('tagline');Each key selector also accepts a closure. Use mapAs(), mapValueAs(), and mapDescriptionAs() when a resolved label, value, or description needs a lookup map or custom closure. Mapping arrays keep the original resolved value when no map entry exists.
Variants
The radio field supports five visual variants:
| Variant | Description |
|---|---|
default | Standard radio buttons with labels |
segmented | Compact horizontal toggle (like iOS segmented control) |
cards | Bordered card boxes |
pills | Pill/tag style |
buttons | Button toolbar style |
You may compare the variants with the same options:
Radio::make('view')->options($views)->variant('default');
Radio::make('view')->options($views)->variant('segmented');
Radio::make('view')->options($views)->variant('cards');
Radio::make('view')->options($views)->variant('pills');
Radio::make('view')->options($views)->variant('buttons');Shortcut methods:
Radio::make('view')->options($views)->segmented();
Radio::make('view')->options($views)->cards();
Radio::make('view')->options($views)->pills();
Radio::make('view')->options($views)->buttons();The buttons() variant submits one radio value, validates against the configured options, and uses radio semantics.
Any other serialized variant falls back to default rendering in Vue and React. This keeps older or custom field data usable without creating an undocumented sixth visual style.
Inline
Display the radio buttons horizontally:
Radio::make('priority')->options([
'low' => 'Low',
'medium' => 'Medium',
'high' => 'High',
])->inline();Columns
Display the options in a multi-column grid. The value is the maximum column target, and the grid automatically drops to fewer columns when the container is too narrow. Pass 1 or higher; lower values throw an InvalidArgumentException.
Radio::make('category')
->options($categories)
->columns(2);Hide Indicator
Hide the radio dot indicator, which is useful for the cards variant:
Radio::make('theme')
->options($themes)
->cards()
->hideIndicator();Or use the explicit method:
Radio::make('theme')
->options($themes)
->showIndicator(false);Size
Set the size of the radio buttons. Available sizes are sm and md (default).
Radio::make('priority')->options($priorities)->size('sm');
Radio::make('priority')->options($priorities)->sm();The serialized PHP default is null, which renders at medium size. Any value other than sm currently uses the medium styles; use sm() or leave the size unset instead of relying on custom size strings.
Using the Component Directly
Radio is exported from each package's components subpath. You may use it for standalone choices, or pass serialized props while rendering forms manually.
<script setup lang="ts">
import { ref } from 'vue'
import { Building2, Rocket } from '@lucide/vue'
import { Radio } from '@inertiaui/form-vue/components'
import type { IconResolverFn } from '@inertiaui/form-vue'
const plan = ref('team')
const icons = { Building2Icon: Building2, RocketIcon: Rocket }
const iconResolver: IconResolverFn = (icon) => icons[icon as keyof typeof icons] ?? null
const plans = [
{ value: 'starter', label: 'Starter', description: 'For small teams.' },
{ value: 'team', label: 'Team', description: 'Most popular.', icon: 'RocketIcon' },
{
value: 'enterprise',
label: 'Enterprise',
description: 'Requires approval.',
icon: 'Building2Icon',
disabled: true,
},
]
</script>
<template>
<Radio
v-model="plan"
id="plan"
name="plan"
label="Plan"
help="Choose the workspace billing plan."
:options="plans"
variant="cards"
:columns="2"
:show-indicator="false"
size="sm"
required
:icon-resolver="iconResolver"
data-testid="plan-radio"
/>
</template>import { useState } from 'react'
import { Building2Icon, RocketIcon } from 'lucide-react'
import type { RadioOption } from '@inertiaui/form-react'
import { Radio } from '@inertiaui/form-react/components'
import type { IconResolverFn } from '@inertiaui/form-react'
const icons = { Building2Icon, RocketIcon }
const iconResolver: IconResolverFn = (icon) => icons[icon as keyof typeof icons] ?? null
const plans: RadioOption[] = [
{ value: 'starter', label: 'Starter', description: 'For small teams.' },
{ value: 'team', label: 'Team', description: 'Most popular.', icon: 'RocketIcon' },
{
value: 'enterprise',
label: 'Enterprise',
description: 'Requires approval.',
icon: 'Building2Icon',
disabled: true,
},
]
export function Plan() {
const [plan, setPlan] = useState<RadioOption['value']>('team')
return (
<Radio
value={plan}
onValueChange={setPlan}
id="plan"
name="plan"
label="Plan"
help="Choose the workspace billing plan."
options={plans}
variant="cards"
columns={2}
showIndicator={false}
size="sm"
required
iconResolver={iconResolver}
data-testid="plan-radio"
/>
)
}Native attributes and listeners target the underlying radiogroup element. See Native Attributes And Events.
Shared field methods remain available. You may use Validation, Conditional Visibility, Icons, and Styling for rules, visibility, icon resolvers, labels, help, layout, and class targets.