View as Markdown

Radio Group

A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.

Loading...
<twig:RadioGroup class="w-fit">
    <div class="flex items-center gap-3">
        <twig:RadioGroup:Item id="r1" name="spacing" value="default" />
        <twig:Label for="r1">Default</twig:Label>
    </div>
    <div class="flex items-center gap-3">
        <twig:RadioGroup:Item id="r2" name="spacing" value="comfortable" checked />
        <twig:Label for="r2">Comfortable</twig:Label>
    </div>
    <div class="flex items-center gap-3">
        <twig:RadioGroup:Item id="r3" name="spacing" value="compact" />
        <twig:Label for="r3">Compact</twig:Label>
    </div>
</twig:RadioGroup>

Installation

php bin/console ux:install radio-group --kit shadcn

Install the following Composer dependencies:

composer require tales-from-a-dev/twig-tailwind-extra:^1.0.0

Copy the following file(s) into your app:

{# @block content The radio items, typically multiple `RadioGroup:Item` components with `Label`. #}
&lt;div
    role=&quot;radiogroup&quot;
    class=&quot;{{ (&#039;grid w-full gap-2 &#039; ~ attributes.render(&#039;class&#039;))|tailwind_merge }}&quot;
    {{ attributes.defaults({
        &#039;data-slot&#039;: &#039;radio-group&#039;,
    }) }}
&gt;
    {%- block content %}{% endblock -%}
&lt;/div&gt;
{# @prop name string The name shared by all radio inputs in the same group. #}
{# @prop value string The value submitted when this item is selected. #}
{%- props name, value -%}
&lt;label class=&quot;{{ (&#039;relative inline-flex size-4 shrink-0 items-center justify-center cursor-pointer group-data-[disabled=true]/field:cursor-not-allowed &#039; ~ attributes.render(&#039;class&#039;))|tailwind_merge }}&quot;&gt;
    &lt;input
        type=&quot;radio&quot;
        name=&quot;{{ name }}&quot;
        value=&quot;{{ value }}&quot;
        class=&quot;peer sr-only&quot;
        {{ attributes.defaults({
            &#039;data-slot&#039;: &#039;radio-group-item&#039;,
        }) }}
    &gt;
    &lt;span class=&quot;flex aspect-square size-4 items-center justify-center rounded-full border border-input outline-none after:absolute after:-inset-x-3 after:-inset-y-2 peer-focus-visible:border-ring peer-focus-visible:ring-3 peer-focus-visible:ring-ring/50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50 peer-aria-invalid:border-destructive peer-aria-invalid:ring-3 peer-aria-invalid:ring-destructive/20 peer-aria-invalid:peer-checked:border-primary dark:bg-input/30 dark:peer-aria-invalid:border-destructive/50 dark:peer-aria-invalid:ring-destructive/40 peer-checked:border-primary peer-checked:bg-primary peer-checked:text-primary-foreground dark:peer-checked:bg-primary&quot;&gt;&lt;/span&gt;
    &lt;span class=&quot;pointer-events-none absolute top-1/2 ltr:left-1/2 rtl:start-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rtl:translate-x-1/2 scale-0 rounded-full bg-primary-foreground transition-transform peer-checked:scale-100&quot;&gt;&lt;/span&gt;
&lt;/label&gt;

Usage

<twig:RadioGroup class="w-fit">
    <div class="flex items-center gap-3">
        <twig:RadioGroup:Item id="option-one" name="option" value="option-one" checked />
        <twig:Label for="option-one">Option One</twig:Label>
    </div>
    <div class="flex items-center gap-3">
        <twig:RadioGroup:Item id="option-two" name="option" value="option-two" />
        <twig:Label for="option-two">Option Two</twig:Label>
    </div>
</twig:RadioGroup>

Examples

Description

Radio group items with a description using the Field component.

Loading...
<twig:RadioGroup class="w-fit">
    <twig:Field orientation="horizontal">
        <twig:RadioGroup:Item id="desc-r1" name="density" value="default" />
        <twig:Field:Content>
            <twig:Field:Label for="desc-r1">Default</twig:Field:Label>
            <twig:Field:Description>Standard spacing for most use cases.</twig:Field:Description>
        </twig:Field:Content>
    </twig:Field>
    <twig:Field orientation="horizontal">
        <twig:RadioGroup:Item id="desc-r2" name="density" value="comfortable" checked />
        <twig:Field:Content>
            <twig:Field:Label for="desc-r2">Comfortable</twig:Field:Label>
            <twig:Field:Description>More space between elements.</twig:Field:Description>
        </twig:Field:Content>
    </twig:Field>
    <twig:Field orientation="horizontal">
        <twig:RadioGroup:Item id="desc-r3" name="density" value="compact" />
        <twig:Field:Content>
            <twig:Field:Label for="desc-r3">Compact</twig:Field:Label>
            <twig:Field:Description>Minimal spacing for dense layouts.</twig:Field:Description>
        </twig:Field:Content>
    </twig:Field>
</twig:RadioGroup>

Choice Card

Use Field:Label to wrap the entire Field for a clickable card-style selection.

Loading...
<twig:RadioGroup class="max-w-sm">
    <twig:Field:Label for="plus-plan" class="border border-input rounded-md has-[:checked]:bg-primary/5 has-[:checked]:border-primary/20 dark:has-[:checked]:bg-primary/10">
        <twig:Field orientation="horizontal" class="p-3">
            <twig:Field:Content>
                <twig:Field:Title>Plus</twig:Field:Title>
                <twig:Field:Description>For individuals and small teams.</twig:Field:Description>
            </twig:Field:Content>
            <twig:RadioGroup:Item id="plus-plan" name="plan" value="plus" checked />
        </twig:Field>
    </twig:Field:Label>
    <twig:Field:Label for="pro-plan" class="border border-input rounded-md has-[:checked]:bg-primary/5 has-[:checked]:border-primary/20 dark:has-[:checked]:bg-primary/10">
        <twig:Field orientation="horizontal" class="p-3">
            <twig:Field:Content>
                <twig:Field:Title>Pro</twig:Field:Title>
                <twig:Field:Description>For growing businesses.</twig:Field:Description>
            </twig:Field:Content>
            <twig:RadioGroup:Item id="pro-plan" name="plan" value="pro" />
        </twig:Field>
    </twig:Field:Label>
    <twig:Field:Label for="enterprise-plan" class="border border-input rounded-md has-[:checked]:bg-primary/5 has-[:checked]:border-primary/20 dark:has-[:checked]:bg-primary/10">
        <twig:Field orientation="horizontal" class="p-3">
            <twig:Field:Content>
                <twig:Field:Title>Enterprise</twig:Field:Title>
                <twig:Field:Description>For large teams and enterprises.</twig:Field:Description>
            </twig:Field:Content>
            <twig:RadioGroup:Item id="enterprise-plan" name="plan" value="enterprise" />
        </twig:Field>
    </twig:Field:Label>
</twig:RadioGroup>

Fieldset

Use Field:Set and Field:Legend to group radio items with a label and description.

Loading...
<twig:Field:Set class="w-full max-w-xs">
    <twig:Field:Legend variant="label">Subscription Plan</twig:Field:Legend>
    <twig:Field:Description>Yearly and lifetime plans offer significant savings.</twig:Field:Description>
    <twig:RadioGroup class="gap-3">
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="plan-monthly" name="subscription" value="monthly" checked />
            <twig:Field:Label for="plan-monthly" class="font-normal">Monthly ($9.99/month)</twig:Field:Label>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="plan-yearly" name="subscription" value="yearly" />
            <twig:Field:Label for="plan-yearly" class="font-normal">Yearly ($99.99/year)</twig:Field:Label>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="plan-lifetime" name="subscription" value="lifetime" />
            <twig:Field:Label for="plan-lifetime" class="font-normal">Lifetime ($299.99)</twig:Field:Label>
        </twig:Field>
    </twig:RadioGroup>
</twig:Field:Set>

Disabled

Use the disabled prop on RadioGroup:Item to disable individual items.

Loading...
<twig:RadioGroup class="w-fit">
    <twig:Field orientation="horizontal" data-disabled="true">
        <twig:RadioGroup:Item id="disabled-1" name="disabled-example" value="option1" disabled />
        <twig:Field:Label for="disabled-1" class="font-normal">Disabled</twig:Field:Label>
    </twig:Field>
    <twig:Field orientation="horizontal">
        <twig:RadioGroup:Item id="disabled-2" name="disabled-example" value="option2" checked />
        <twig:Field:Label for="disabled-2" class="font-normal">Option 2</twig:Field:Label>
    </twig:Field>
    <twig:Field orientation="horizontal">
        <twig:RadioGroup:Item id="disabled-3" name="disabled-example" value="option3" />
        <twig:Field:Label for="disabled-3" class="font-normal">Option 3</twig:Field:Label>
    </twig:Field>
</twig:RadioGroup>

Invalid

Use aria-invalid on RadioGroup:Item and data-invalid on Field to show validation errors.

Loading...
<twig:Field:Set class="w-full max-w-xs">
    <twig:Field:Legend variant="label">Notification Preferences</twig:Field:Legend>
    <twig:Field:Description>Choose how you want to receive notifications.</twig:Field:Description>
    <twig:RadioGroup>
        <twig:Field orientation="horizontal" data-invalid="true">
            <twig:RadioGroup:Item id="invalid-email" name="notifications" value="email" checked aria-invalid="true" />
            <twig:Field:Label for="invalid-email" class="font-normal">Email only</twig:Field:Label>
        </twig:Field>
        <twig:Field orientation="horizontal" data-invalid="true">
            <twig:RadioGroup:Item id="invalid-sms" name="notifications" value="sms" aria-invalid="true" />
            <twig:Field:Label for="invalid-sms" class="font-normal">SMS only</twig:Field:Label>
        </twig:Field>
        <twig:Field orientation="horizontal" data-invalid="true">
            <twig:RadioGroup:Item id="invalid-both" name="notifications" value="both" aria-invalid="true" />
            <twig:Field:Label for="invalid-both" class="font-normal">Both Email &amp; SMS</twig:Field:Label>
        </twig:Field>
    </twig:RadioGroup>
</twig:Field:Set>

RTL

To enable RTL support, set the dir="rtl" attribute on the root element.

Loading...
<div class="flex flex-col gap-8">
    <twig:RadioGroup class="w-fit" dir="rtl">
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r1-rtl-ar" name="density-rtl-ar" value="default" dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r1-rtl-ar" dir="rtl">افتراضي</twig:Field:Label>
                <twig:Field:Description dir="rtl">تباعد قياسي لمعظم حالات الاستخدام.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r2-rtl-ar" name="density-rtl-ar" value="comfortable" checked dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r2-rtl-ar" dir="rtl">مريح</twig:Field:Label>
                <twig:Field:Description dir="rtl">مساحة أكبر بين العناصر.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r3-rtl-ar" name="density-rtl-ar" value="compact" dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r3-rtl-ar" dir="rtl">مضغوط</twig:Field:Label>
                <twig:Field:Description dir="rtl">تباعد أدنى للتخطيطات الكثيفة.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
    </twig:RadioGroup>
    <twig:RadioGroup class="w-fit" dir="rtl">
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r1-rtl-he" name="density-rtl-he" value="default" dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r1-rtl-he" dir="rtl">ברירת מחדל</twig:Field:Label>
                <twig:Field:Description dir="rtl">ריווח סטנדרטי לרוב מקרי השימוש.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r2-rtl-he" name="density-rtl-he" value="comfortable" checked dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r2-rtl-he" dir="rtl">נוח</twig:Field:Label>
                <twig:Field:Description dir="rtl">יותר מקום בין האלמנטים.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
        <twig:Field orientation="horizontal">
            <twig:RadioGroup:Item id="r3-rtl-he" name="density-rtl-he" value="compact" dir="rtl" />
            <twig:Field:Content>
                <twig:Field:Label for="r3-rtl-he" dir="rtl">דחוס</twig:Field:Label>
                <twig:Field:Description dir="rtl">ריווח מינימלי לממשקים דחוסים.</twig:Field:Description>
            </twig:Field:Content>
        </twig:Field>
    </twig:RadioGroup>
</div>

API Reference

<twig:RadioGroup>

Block Description
content The radio items, typically multiple RadioGroup:Item components with Label.

<twig:RadioGroup:Item>

Prop Type Default
name 
string -
value 
string -