<fieldset>
<legend>Favourite Flavour</legend>
<p class="field__hint" id="flavour-hint">Please choose a flavour of ice cream.</p>
<div class="field">
<input type="radio" id="flavour-chocolate" name="flavour" value="chocolate" aria-describedby="flavour-hint" checked />
<label for="flavour-chocolate">Chocolate</label>
</div>
<div class="field">
<input type="radio" id="flavour-vanilla" name="flavour" value="vanilla" aria-describedby="flavour-hint" />
<label for="flavour-vanilla">Vanilla</label>
</div>
<div class="field">
<input type="radio" id="flavour-strawberry" name="flavour" value="strawberry" aria-describedby="flavour-hint" />
<label for="flavour-strawberry">Strawberry</label>
</div>
</fieldset>
{% set ariaDescribedby = '' %}
{% if hint %}
{% set ariaDescribedby = name + '-hint' %}
{% elif error %}
{% set ariaDescribedby = name + '-error' %}
{% elif hint and error %}
{% set ariaDescribedby = name + '-hint' + " " + name + '-error' %}
{% endif %}
<fieldset{% if error %} class="field--error"{% endif %}>
<legend>{{ legend }}</legend>
{%- if hint %}
{% render '@hint', { name: name, content: hint } %}
{%- endif %}
{%- for value, label in options -%}
<div class="field">
<input type="radio" id="{{ name }}-{{ value }}" name="{{ name }}" value="{{ value }}" {% if ariaDescribedby != '' %}aria-describedby="{{ ariaDescribedby }}" {% endif %}{% if error %} aria-invalid="true"{% endif %} {% if default == value %} checked{% endif %}/>
<label for="{{ name }}-{{ value }}">{{ label }}</label>
</div>
{%- endfor -%}
{%- if error %}
{% render '@error', { name: name, content: error } %}
{%- endif -%}
</fieldset>
{
"name": "flavour",
"legend": "Favourite Flavour",
"hint": "Please choose a flavour of ice cream.",
"error": false,
"default": "chocolate",
"options": {
"chocolate": "Chocolate",
"vanilla": "Vanilla",
"strawberry": "Strawberry"
}
}
Radio buttons are visually hidden and replaced with custom style via pseudo content attached to the adjacent label:
input[type="radio"] {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
input[type="radio"] + label::before {
/* Custom radio button style. */
}Labels and the corresponding radio button element are intended to be wrapped in a containing element of some sort, ideally a paragraph.
A group of radio buttons is wrapped in a fieldset with a legend which names
the input group. This technique is derived from WebAIM’s article,
Accessible Form Controls.
A hint for the group can be added immediately after the <legend> in a
paragraph with a class of field__hint.
A validation error message for the group can be added immediately after the last
checkbox in a paragraph with a class of field__error.
Hints and validation error messages must be associated with the radio buttons
using unique IDs which can be referenced from the radio buttons’
aria-describedby attributes. For more information, see WebAIM’s form
validation error documentation.
Radio buttons with an associated error should also be given an aria-invalid
attribute of true.