Skip to content

Radio Group

Radio group
Thymeleaf source
<p id="plan-question">Plan</p>
<sl:radio-group aria-labelledby="plan-question">
<sl:label th:each="plan : ${plans}">
<sl:radio-group-item th:field="*{plan}" th:value="${plan}"/>
<th:block th:text="#{|plan.${plan}|}">Free</th:block>
</sl:label>
</sl:radio-group>
Rendered HTML
<p id="plan-question">Plan</p>
<div class="radio-group" role="radiogroup" aria-labelledby="plan-question">
<label class="label">
<input type="radio" class="radio-group-item" name="plan" value="free" checked>
Free
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="plan" value="pro">
Pro
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="plan" value="enterprise">
Enterprise
</label>
</div>

Write th:field on every item, with the item’s own value or th:value. Spring gives them the field’s name, numbers their ids (plan1, plan2, …) and checks the one whose value matches the field. Because of the numbered ids, put each item inside its label.

The group is announced as a radio group. Name it with aria-labelledby, pointing at the question, or with aria-label.

In a field set, th:field goes on the field set once, and the items take it. Its legend asks the question, and it shows the error message and describes the group with it.

Horizontal
Thymeleaf source
<sl:radio-group orientation="horizontal" aria-label="Density">
<sl:label><sl:radio-group-item name="density" value="compact"/>Compact</sl:label>
<sl:label><sl:radio-group-item name="density" value="comfortable" checked/>Comfortable</sl:label>
<sl:label><sl:radio-group-item name="density" value="spacious"/>Spacious</sl:label>
</sl:radio-group>
Rendered HTML
<div class="radio-group" role="radiogroup" data-orientation="horizontal" aria-label="Density">
<label class="label">
<input type="radio" class="radio-group-item" name="density" value="compact">
Compact
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="density" value="comfortable" checked>
Comfortable
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="density" value="spacious">
Spacious
</label>
</div>

A field with errors marks every item aria-invalid="true".

InvalidWith th:field, a field that has errors marks every item aria-invalid by itself.
Thymeleaf source
<sl:radio-group aria-label="Delivery">
<sl:label><sl:radio-group-item th:field="*{delivery}" value="standard"/>Standard</sl:label>
<sl:label><sl:radio-group-item th:field="*{delivery}" value="express"/>Express</sl:label>
</sl:radio-group>
Rendered HTML
<div class="radio-group" role="radiogroup" aria-label="Delivery">
<label class="label">
<input type="radio" class="radio-group-item" name="delivery" value="standard" aria-invalid="true">
Standard
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="delivery" value="express" aria-invalid="true">
Express
</label>
</div>

A disabled radio button and its label fade, and the keyboard skips it. To disable the whole group, put it in a field set with disabled.

Disabled item
Thymeleaf source
<sl:radio-group aria-label="Shipping">
<sl:label><sl:radio-group-item name="shipping" value="pickup" checked/>Pick up in store</sl:label>
<sl:label><sl:radio-group-item name="shipping" value="drone" disabled/>Drone (not available)</sl:label>
</sl:radio-group>
Rendered HTML
<div class="radio-group" role="radiogroup" aria-label="Shipping">
<label class="label">
<input type="radio" class="radio-group-item" name="shipping" value="pickup" checked>
Pick up in store
</label>
<label class="label">
<input type="radio" class="radio-group-item" name="shipping" value="drone" disabled>
Drone (not available)
</label>
</div>
AttributeValuesDefaultDescription
orientationvertical horizontalverticalStack the items, or put them on a row that wraps.

Every prop can also be set from an expression: th:orientation="${...}". Any other attribute passes through to the rendered element, and class is appended.

sl:radio-group-item declares no props; every attribute passes through.