Skip to content

RadioGroup

component

Radio buttons that share a name: the browser checks one at a time, moves between them with the arrows and submits it, without JavaScript.

Preview

Light

Code
<twig:RadioGroup name="plan" value="pro" aria-label="Plan">
    <twig:RadioGroup:Item value="free" id="plan-free" /><twig:Label for="plan-free">Free</twig:Label>
    <twig:RadioGroup:Item value="pro" id="plan-pro" /><twig:Label for="plan-pro">Pro</twig:Label>
</twig:RadioGroup>

Dark

Code
<twig:RadioGroup name="plan" value="pro" aria-label="Plan">
    <twig:RadioGroup:Item value="free" id="plan-free" /><twig:Label for="plan-free">Free</twig:Label>
    <twig:RadioGroup:Item value="pro" id="plan-pro" /><twig:Label for="plan-pro">Pro</twig:Label>
</twig:RadioGroup>

Try it

Change the props; the example is rendered again by the server.

<twig:RadioGroup name="plan" value="pro" aria-label="Plan">
    <twig:RadioGroup:Item value="free" id="plan-free" /><twig:Label for="plan-free">Free</twig:Label>
    <twig:RadioGroup:Item value="pro" id="plan-pro" /><twig:Label for="plan-pro">Pro</twig:Label>
</twig:RadioGroup>

Variants

orientation

The direction in which the radio buttons are laid out.

orientation="vertical"
orientation="horizontal"

disabled

Whether every radio button is disabled.

disabled="false"
disabled="true"

required

Whether a value must be checked before the form can be submitted.

required="false"
required="true"

Installation

php bin/console ux:install radio-group --kit=github.com/parler-haut-interagir-librement/ux-kit

Props

PropTypeDefaultDescription
value string|null null The value checked on initial render.
orientation 'vertical'|'horizontal' 'vertical' The direction in which the radio buttons are laid out.
disabled bool false Whether every radio button is disabled.
required bool false Whether a value must be checked before the form can be submitted.

Accessibility

The group has the role radiogroup; name it with aria-label or aria-labelledby, and each radio button with a Label. One Tab reaches the group, the arrows move inside it.

Files to copy

templates/components/RadioGroup.html.twig
{#-
 # Radio buttons that share a name: the browser checks one at a time, moves between them with the arrows and submits
 # the one checked, without JavaScript.
 #}
{%- props
    ## string The name of the form field the radio buttons share.
    name,
    ## string|null The value checked on initial render.
    value = null,
    ## 'vertical'|'horizontal' The direction in which the radio buttons are laid out.
    orientation = 'vertical',
    ## bool Whether every radio button is disabled.
    disabled = false,
    ## bool Whether a value must be checked before the form can be submitted.
    required = false
-%}
{%- set _horizontal = orientation is same as('horizontal') -%}
{%- do provide('radioGroup.name', name) -%}
{%- do provide('radioGroup.value', value) -%}
{%- do provide('radioGroup.disabled', disabled) -%}
{%- do provide('radioGroup.required', required) -%}
<div role="radiogroup" data-slot="radio-group" data-orientation="{{ _horizontal ? 'horizontal' : 'vertical' }}"{{ attributes.defaults({class: 'isRadioGroup' ~ (_horizontal ? ' isHorizontal' : '')}) }}>
{##- The radio buttons, each a `RadioGroup:Item` named by a `Label`. -#}
{%- block content %}{% endblock -%}
</div>
templates/components/RadioGroup/Item.html.twig
{%- props
    ## string The value submitted when this radio button is checked.
    value,
    ## bool Whether this radio button is disabled.
    disabled = false
-%}
<input type="radio" data-slot="radio-group-item" name="{{ inject('radioGroup.name') }}" value="{{ value }}"{% if value is same as(inject('radioGroup.value')) %} checked{% endif %}{% if disabled or inject('radioGroup.disabled') %} disabled{% endif %}{% if inject('radioGroup.required') %} required{% endif %}{{ attributes }}>