Radio Button

Single-select radio groups — default, custom styled, card-style, list group, and inline vs stacked layouts.

All radio groups use native <input type="radio"> elements styled via DaisyUI's radio class. Alpine.js is used only where reactive state adds visible value — size/color pickers and the card-style selector. Simple list groups are pure HTML so they work without JavaScript.

1 — Default

Stock DaisyUI radio in a fieldset with a legend. No JS required. Stacked (default) and inline layouts shown side by side, plus all six color tokens.

Stacked
Inline
Color tokens
<!-- Stacked (default) -->
<fieldset class="fieldset">
    <legend class="fieldset-legend">Billing frequency</legend>

    <label class="fieldset-label cursor-pointer">
        <input type="radio" name="frequency" value="weekly"
               class="radio radio-sm radio-primary" checked />
        <span class="text-sm">Weekly</span>
    </label>

    <label class="fieldset-label cursor-pointer">
        <input type="radio" name="frequency" value="monthly"
               class="radio radio-sm radio-primary" />
        <span class="text-sm">Monthly</span>
    </label>
</fieldset>

<!-- Inline -->
<fieldset class="fieldset">
    <legend class="fieldset-legend">Size</legend>
    <div class="flex flex-wrap gap-4">
        <label class="flex items-center gap-2 cursor-pointer">
            <input type="radio" name="size" value="sm"
                   class="radio radio-sm radio-primary" />
            <span class="text-sm">Small</span>
        </label>
        <!-- … -->
    </div>
</fieldset>

2 — Sizes

Five size steps via DaisyUI size modifiers. No custom CSS required — all are Tailwind-composable with other radio-* tokens.

3 — With Description Text

Label + helper text pattern. The radio aligns to the first line of the label; the description sits beneath using standard Tailwind utility classes.

Notification preference
Shipping method
<fieldset class="fieldset gap-0">
    <legend class="fieldset-legend mb-1">Shipping method</legend>

    <label class="flex items-center gap-3 cursor-pointer py-2.5
                  border-b border-base-200 last:border-0">
        <input type="radio" name="shipping" value="standard"
               class="radio radio-sm radio-primary shrink-0" checked />
        <span class="flex-1 min-w-0">
            <span class="flex justify-between items-baseline gap-2">
                <span class="text-sm font-medium">Standard Shipping</span>
                <span class="text-sm font-semibold text-primary">Free</span>
            </span>
            <span class="text-xs text-base-content/50">5–7 business days</span>
        </span>
    </label>

    <!-- repeat for each option … -->
</fieldset>

4 — Card-style

The entire card is the clickable label. Alpine tracks the selected value so the card border and radio reflect the same state without duplicating logic. The hidden native <input> stays accessible via keyboard.

Compact — shipping method

Full card — pricing plan

<div x-data="{ selected: 'pro' }" class="grid grid-cols-3 gap-3">

    <!-- Repeat this label for each plan -->
    <label
        class="relative flex flex-col gap-3 p-4 border rounded-[--radius-sm]
               cursor-pointer transition-colors"
        :class="selected === 'pro'
            ? 'border-primary bg-primary/5 ring-1 ring-primary/30'
            : 'border-base-300 bg-base-100 hover:border-base-400'"
    >
        <input type="radio" name="plan" value="pro"
               class="radio radio-sm radio-primary"
               x-model="selected" />

        <div>
            <p class="font-semibold text-sm">Pro</p>
            <p class="text-xl font-bold mt-0.5">
                $19 <span class="text-sm font-normal text-base-content/50">/mo</span>
            </p>
        </div>

        <ul class="flex flex-col gap-1">
            <li class="flex items-center gap-1.5 text-xs text-base-content/70">
                <span class="text-success">✓</span> 10 projects
            </li>
            <!-- … -->
        </ul>
    </label>

</div>

5 — Radio List Group

Each row is a full-width tappable area inside a bordered container — the same pattern used in mobile settings UIs. Row highlight on selection uses Alpine; the border container is a custom shell since DaisyUI's menu is for navigation, not radio groups.

Default

With icon

<div x-data="{ selected: 'mentions' }">
    <div class="border border-base-300 rounded-[--radius-sm] overflow-hidden
                divide-y divide-base-200">

        <label class="flex items-center gap-3 px-4 py-3 cursor-pointer transition-colors"
               :class="selected === 'all' ? 'bg-primary/5' : 'bg-base-100 hover:bg-base-200'">
            <input type="radio" name="notif" value="all"
                   class="radio radio-sm radio-primary"
                   x-model="selected" />
            <span class="text-sm">All activity</span>
        </label>

        <!-- repeat for each option … -->
    </div>
</div>

6 — States

Disabled (whole group and individual option), error with validation message, and a loading placeholder skeleton.

Disabled group

Error / required

Gender *

Please select an option.

Loading