Skip to content
Praesepe UI

forms

Radio

Native radio option with inline default layout or selectable card panels, label, description, and attribute forwarding.

Copied!

Examples

Inline group

Default variant as a vertical radio list.

Copied!
Billing cycle
<fieldset class="max-w-sm space-y-3">
    <legend class="text-sm font-medium text-fg">Billing cycle</legend>
    <x-ui.radio name="cycle" value="monthly" label="Monthly" checked />
    <x-ui.radio name="cycle" value="yearly" label="Yearly" />
</fieldset>
<fieldset class="max-w-sm space-y-3">
    <legend class="text-sm font-medium text-fg">Billing cycle</legend>
    <div class="inline-flex items-start gap-3">
        <div class="relative mt-0.5 inline-flex size-4 shrink-0">
            <input id="cycle-monthly" type="radio" name="cycle" value="monthly" checked class="peer absolute inset-0 z-10 size-4 cursor-pointer opacity-0">
            <span class="pointer-events-none flex size-4 items-center justify-center rounded-full border border-border-strong bg-surface-raised shadow-sm peer-checked:border-brand peer-checked:[&_.dot]:opacity-100" aria-hidden="true">
                <span class="dot size-2 rounded-full bg-brand opacity-0"></span>
            </span>
        </div>
        <label for="cycle-monthly" class="text-sm font-medium text-fg">Monthly</label>
    </div>
    <div class="inline-flex items-start gap-3">
        <div class="relative mt-0.5 inline-flex size-4 shrink-0">
            <input id="cycle-yearly" type="radio" name="cycle" value="yearly" class="peer absolute inset-0 z-10 size-4 cursor-pointer opacity-0">
            <span class="pointer-events-none flex size-4 items-center justify-center rounded-full border border-border-strong bg-surface-raised shadow-sm peer-checked:border-brand peer-checked:[&_.dot]:opacity-100" aria-hidden="true">
                <span class="dot size-2 rounded-full bg-brand opacity-0"></span>
            </span>
        </div>
        <label for="cycle-yearly" class="text-sm font-medium text-fg">Yearly</label>
    </div>
</fieldset>

Card variant

Selectable panels highlighted with :has(input:checked).

Copied!
Deployment region
<fieldset class="grid max-w-xl gap-3 sm:grid-cols-2">
    <legend class="mb-1 text-sm font-medium text-fg">Deployment region</legend>
    <x-ui.radio
        variant="card"
        name="region"
        value="sg"
        label="Singapore"
        description="Lowest latency for SEA users."
        checked
    />
    <x-ui.radio
        variant="card"
        name="region"
        value="eu"
        label="Frankfurt"
        description="EU data residency friendly."
    />
</fieldset>
<fieldset class="grid max-w-xl gap-3 sm:grid-cols-2">
    <legend class="mb-1 text-sm font-medium text-fg">Deployment region</legend>
    <label class="flex cursor-pointer items-start gap-3 rounded-card border border-border bg-surface-raised p-4 shadow-sm has-[:checked]:border-brand has-[:checked]:bg-brand/5">
        <span class="relative mt-0.5 inline-flex size-4 shrink-0">
            <input id="region-sg" type="radio" name="region" value="sg" checked class="peer absolute inset-0 z-10 size-4 cursor-pointer opacity-0">
            <span class="pointer-events-none flex size-4 items-center justify-center rounded-full border border-border-strong bg-surface-raised shadow-sm peer-checked:border-brand peer-checked:[&_.dot]:opacity-100" aria-hidden="true">
                <span class="dot size-2 rounded-full bg-brand opacity-0"></span>
            </span>
        </span>
        <span>
            <span class="block text-sm font-medium text-fg">Singapore</span>
            <span class="mt-0.5 block text-sm text-fg-muted">Lowest latency for SEA users.</span>
        </span>
    </label>
    <label class="flex cursor-pointer items-start gap-3 rounded-card border border-border bg-surface-raised p-4 shadow-sm has-[:checked]:border-brand has-[:checked]:bg-brand/5">
        <span class="relative mt-0.5 inline-flex size-4 shrink-0">
            <input id="region-eu" type="radio" name="region" value="eu" class="peer absolute inset-0 z-10 size-4 cursor-pointer opacity-0">
            <span class="pointer-events-none flex size-4 items-center justify-center rounded-full border border-border-strong bg-surface-raised shadow-sm peer-checked:border-brand peer-checked:[&_.dot]:opacity-100" aria-hidden="true">
                <span class="dot size-2 rounded-full bg-brand opacity-0"></span>
            </span>
        </span>
        <span>
            <span class="block text-sm font-medium text-fg">Frankfurt</span>
            <span class="mt-0.5 block text-sm text-fg-muted">EU data residency friendly.</span>
        </span>
    </label>
</fieldset>

Disabled option

Disabled state on a single option.

Copied!

Contact sales to unlock this plan.

<x-ui.radio
    name="plan_demo"
    value="enterprise"
    label="Enterprise"
    description="Contact sales to unlock this plan."
    disabled
/>
<div class="inline-flex items-start gap-3 opacity-50">
    <div class="relative mt-0.5 inline-flex size-4 shrink-0">
        <input id="plan-enterprise" type="radio" name="plan_demo" value="enterprise" disabled class="peer absolute inset-0 z-10 size-4 cursor-not-allowed opacity-0">
        <span class="pointer-events-none flex size-4 items-center justify-center rounded-full border border-border-strong bg-surface-raised shadow-sm" aria-hidden="true">
            <span class="size-2 rounded-full bg-brand opacity-0"></span>
        </span>
    </div>
    <div>
        <label for="plan-enterprise" class="block text-sm font-medium text-fg">Enterprise</label>
        <p class="mt-0.5 text-sm text-fg-muted">Contact sales to unlock this plan.</p>
    </div>
</div>

Props API

Component props
Prop Type Default Description
variant default|card default Inline list item or bordered selectable card. Cards highlight with :has(input:checked).
label string|null null Visible label linked via for/id (or wrapping label for card).
description string|null null Supporting text referenced by aria-describedby.

Accessibility notes

Architected with WCAG 2.2 AA patterns in mind. These notes document the exact keyboard and ARIA behavior for this component.

  • Uses a native radio input so arrow keys move within a name group and Space selects the focused option.
  • Default variant links label for to input id. Card variant wraps the control in a label for a larger hit target.
  • Description is linked with aria-describedby when provided.
  • Pass-through attributes (name, value, checked, disabled, required, x-model, wire:model) land on the input.
  • Compose a group by rendering multiple radios that share the same name.
  • Keyboard: Tab enters the group. Arrow keys change the selected option within the group.

Built by Praesepe

Architecture & custom software partner

Praesepe uses these exact UI primitives to ship SME dashboards, inventory systems, invoicing desks, and internal tools faster, without rebuilding a design system for every client.

  • Same Blade + Tailwind 4 + Alpine 3 stack you see in this docs site
  • Opinionated for Indonesian SME ops: invoices, stock, roles, approvals
  • Architected with WCAG 2.2 AA patterns in mind for keyboard and ARIA

Talk to the studio

WhatsApp: TODO Email the studio Visit Praesepe