Toggle Group
Thymeleaf source
<sl:toggle-group type="multiple" name="textStyle" aria-label="Text style"> <sl:toggle-group-item value="bold" aria-label="Bold"><sl:icon name="bold"/></sl:toggle-group-item> <sl:toggle-group-item value="italic" aria-label="Italic"><sl:icon name="italic"/></sl:toggle-group-item> <sl:toggle-group-item value="underline" aria-label="Underline"><sl:icon name="underline"/></sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="group" aria-label="Text style"> <label class="toggle toggle-group-item"> <input class="toggle-input" type="checkbox" name="textStyle" value="bold" aria-label="Bold"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8"></path> </svg> </label> <label class="toggle toggle-group-item"> <input class="toggle-input" type="checkbox" name="textStyle" value="italic" aria-label="Italic"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <line x1="19" x2="10" y1="4" y2="4"></line> <line x1="14" x2="5" y1="20" y2="20"></line> <line x1="15" x2="9" y1="4" y2="20"></line> </svg> </label> <label class="toggle toggle-group-item"> <input class="toggle-input" type="checkbox" name="textStyle" value="underline" aria-label="Underline"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M6 4v6a6 6 0 0 0 12 0V4"></path> <line x1="4" x2="20" y1="20" y2="20"></line> </svg> </label></div>The items of a toggle group are toggles around radio buttons (type="single", the default: one item is
on at a time) or checkboxes (type="multiple": any number). The form submits them as such inputs, and they work
without JavaScript. In a single group the arrow keys move between the items and Tab leaves the group, as in any
group of radio buttons; in a multiple group every item is a tab stop.
Name the group with aria-label, or with aria-labelledby pointing at its label. Give each item a value; an item
that holds only an icon needs an aria-label.
Outline
Section titled “Outline”Thymeleaf source
<sl:toggle-group variant="outline" name="callFilter" aria-label="Calls"> <sl:toggle-group-item value="all" checked>All</sl:toggle-group-item> <sl:toggle-group-item value="missed">Missed</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" aria-label="Calls"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="callFilter" value="all" checked> All </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="callFilter" value="missed"> Missed </label></div>In a form
Section titled “In a form”Write th:field on the group, once. The items share it: Spring gives them the field’s name, numbers their ids
(layout1, layout2, …) and checks the one whose value matches the field. Without a form object, name on the
group gives the items their name. A single group with neither gets a generated name, so its items still exclude
each other; give it a name when the form should submit it.
Thymeleaf source
<p id="layout-label">Layout</p><sl:toggle-group th:field="*{layout}" variant="outline" aria-labelledby="layout-label"> <sl:toggle-group-item value="list"><sl:icon name="list"/> List</sl:toggle-group-item> <sl:toggle-group-item value="grid"><sl:icon name="layout-grid"/> Grid</sl:toggle-group-item> <sl:toggle-group-item value="table"><sl:icon name="table-2"/> Table</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<p id="layout-label">Layout</p><div class="toggle-group" role="radiogroup" aria-labelledby="layout-label"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" value="list" id="layout1" name="layout"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M3 5h.01"></path> <path d="M3 12h.01"></path> <path d="M3 19h.01"></path> <path d="M8 5h13"></path> <path d="M8 12h13"></path> <path d="M8 19h13"></path> </svg> List </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" value="grid" id="layout2" name="layout" checked> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <rect width="7" height="7" x="3" y="3" rx="1"></rect> <rect width="7" height="7" x="14" y="3" rx="1"></rect> <rect width="7" height="7" x="14" y="14" rx="1"></rect> <rect width="7" height="7" x="3" y="14" rx="1"></rect> </svg> Grid </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" value="table" id="layout3" name="layout"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M3 9h18"></path> <path d="M9 3v18"></path> <rect x="3" y="3" width="18" height="18" rx="2"></rect> </svg> Table </label></div>In a field set with th:field, the group takes the field set’s, and
the legend labels it.
Multiple
Section titled “Multiple”With type="multiple", bind a collection (a List, a Set, an array). Spring checks every item whose value is in
it, and adds a hidden marker input, so a form with no item on clears the collection.
Thymeleaf source
<sl:toggle-group type="multiple" th:field="*{workdays}" variant="outline" aria-label="Workdays"> <sl:toggle-group-item value="MONDAY">Mon</sl:toggle-group-item> <sl:toggle-group-item value="TUESDAY">Tue</sl:toggle-group-item> <sl:toggle-group-item value="WEDNESDAY">Wed</sl:toggle-group-item> <sl:toggle-group-item value="THURSDAY">Thu</sl:toggle-group-item> <sl:toggle-group-item value="FRIDAY">Fri</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="group" aria-label="Workdays"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="checkbox" value="MONDAY" id="workdays1" name="workdays" checked> <input type="hidden" name="_workdays" value="on"> Mon </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="checkbox" value="TUESDAY" id="workdays2" name="workdays" checked> <input type="hidden" name="_workdays" value="on"> Tue </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="checkbox" value="WEDNESDAY" id="workdays3" name="workdays"> <input type="hidden" name="_workdays" value="on"> Wed </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="checkbox" value="THURSDAY" id="workdays4" name="workdays" checked> <input type="hidden" name="_workdays" value="on"> Thu </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="checkbox" value="FRIDAY" id="workdays5" name="workdays"> <input type="hidden" name="_workdays" value="on"> Fri </label></div>Thymeleaf source
<sl:toggle-group size="sm" variant="outline" spacing="0" name="positionSm" aria-label="Position, small"> <sl:toggle-group-item value="top" checked>Top</sl:toggle-group-item> <sl:toggle-group-item value="bottom">Bottom</sl:toggle-group-item></sl:toggle-group><sl:toggle-group variant="outline" spacing="0" name="positionDefault" aria-label="Position"> <sl:toggle-group-item value="top" checked>Top</sl:toggle-group-item> <sl:toggle-group-item value="bottom">Bottom</sl:toggle-group-item></sl:toggle-group><sl:toggle-group size="lg" variant="outline" spacing="0" name="positionLg" aria-label="Position, large"> <sl:toggle-group-item value="top" checked>Top</sl:toggle-group-item> <sl:toggle-group-item value="bottom">Bottom</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" data-spacing="0" aria-label="Position, small"> <label class="toggle toggle-group-item" data-variant="outline" data-size="sm"> <input class="toggle-input" type="radio" name="positionSm" value="top" checked> Top </label> <label class="toggle toggle-group-item" data-variant="outline" data-size="sm"> <input class="toggle-input" type="radio" name="positionSm" value="bottom"> Bottom </label></div><div class="toggle-group" role="radiogroup" data-spacing="0" aria-label="Position"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="positionDefault" value="top" checked> Top </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="positionDefault" value="bottom"> Bottom </label></div><div class="toggle-group" role="radiogroup" data-spacing="0" aria-label="Position, large"> <label class="toggle toggle-group-item" data-variant="outline" data-size="lg"> <input class="toggle-input" type="radio" name="positionLg" value="top" checked> Top </label> <label class="toggle toggle-group-item" data-variant="outline" data-size="lg"> <input class="toggle-input" type="radio" name="positionLg" value="bottom"> Bottom </label></div>Spacing
Section titled “Spacing”spacing sets the gap between the items, in Tailwind’s spacing steps: 2 (0.5rem) by default, 0 to join them
into one control.
Thymeleaf source
<sl:toggle-group variant="outline" spacing="0" name="alignment" aria-label="Alignment"> <sl:toggle-group-item value="left" checked aria-label="Align left"><sl:icon name="align-left"/></sl:toggle-group-item> <sl:toggle-group-item value="center" aria-label="Align center"><sl:icon name="align-center"/></sl:toggle-group-item> <sl:toggle-group-item value="right" aria-label="Align right"><sl:icon name="align-right"/></sl:toggle-group-item></sl:toggle-group><sl:toggle-group variant="outline" spacing="4" name="alignmentSpaced" aria-label="Alignment, spaced"> <sl:toggle-group-item value="left" checked aria-label="Align left"><sl:icon name="align-left"/></sl:toggle-group-item> <sl:toggle-group-item value="center" aria-label="Align center"><sl:icon name="align-center"/></sl:toggle-group-item> <sl:toggle-group-item value="right" aria-label="Align right"><sl:icon name="align-right"/></sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" data-spacing="0" aria-label="Alignment"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignment" value="left" checked aria-label="Align left"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M15 12H3"></path> <path d="M17 19H3"></path> </svg> </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignment" value="center" aria-label="Align center"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M17 12H7"></path> <path d="M19 19H5"></path> </svg> </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignment" value="right" aria-label="Align right"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M21 12H9"></path> <path d="M21 19H7"></path> </svg> </label></div><div class="toggle-group" role="radiogroup" data-spacing="4" aria-label="Alignment, spaced"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignmentSpaced" value="left" checked aria-label="Align left"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M15 12H3"></path> <path d="M17 19H3"></path> </svg> </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignmentSpaced" value="center" aria-label="Align center"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M17 12H7"></path> <path d="M19 19H5"></path> </svg> </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="alignmentSpaced" value="right" aria-label="Align right"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M21 12H9"></path> <path d="M21 19H7"></path> </svg> </label></div>Vertical
Section titled “Vertical”Thymeleaf source
<sl:toggle-group orientation="vertical" variant="outline" spacing="0" name="rowDensity" aria-label="Density"> <sl:toggle-group-item value="compact">Compact</sl:toggle-group-item> <sl:toggle-group-item value="comfortable" checked>Comfortable</sl:toggle-group-item> <sl:toggle-group-item value="spacious">Spacious</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" data-spacing="0" data-orientation="vertical" aria-label="Density"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="rowDensity" value="compact"> Compact </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="rowDensity" value="comfortable" checked> Comfortable </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="rowDensity" value="spacious"> Spacious </label></div>Invalid
Section titled “Invalid”A field with errors marks every item aria-invalid="true".
Thymeleaf source
<sl:toggle-group th:field="*{shippingSpeed}" variant="outline" aria-label="Shipping"> <sl:toggle-group-item value="standard">Standard</sl:toggle-group-item> <sl:toggle-group-item value="express">Express</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" aria-label="Shipping"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" aria-invalid="true" value="standard" id="shippingSpeed1" name="shippingSpeed"> Standard </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" aria-invalid="true" value="express" id="shippingSpeed2" name="shippingSpeed"> Express </label></div>Disabled
Section titled “Disabled”Thymeleaf source
<sl:toggle-group type="multiple" disabled name="textStyleLocked" aria-label="Text style (locked)"> <sl:toggle-group-item value="bold" checked aria-label="Bold"><sl:icon name="bold"/></sl:toggle-group-item> <sl:toggle-group-item value="italic" aria-label="Italic"><sl:icon name="italic"/></sl:toggle-group-item></sl:toggle-group><sl:toggle-group variant="outline" name="billingPeriod" aria-label="Plan"> <sl:toggle-group-item value="monthly" checked>Monthly</sl:toggle-group-item> <sl:toggle-group-item value="yearly" disabled>Yearly</sl:toggle-group-item></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="group" aria-label="Text style (locked)"> <label class="toggle toggle-group-item"> <input class="toggle-input" type="checkbox" name="textStyleLocked" value="bold" checked aria-label="Bold" disabled> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8"></path> </svg> </label> <label class="toggle toggle-group-item"> <input class="toggle-input" type="checkbox" name="textStyleLocked" value="italic" aria-label="Italic" disabled> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <line x1="19" x2="10" y1="4" y2="4"></line> <line x1="14" x2="5" y1="20" y2="20"></line> <line x1="15" x2="9" y1="4" y2="20"></line> </svg> </label></div><div class="toggle-group" role="radiogroup" aria-label="Plan"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="billingPeriod" value="monthly" checked> Monthly </label> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="billingPeriod" value="yearly" disabled> Yearly </label></div>With tooltips
Section titled “With tooltips”Put an item in a tooltip. The group still joins the items, the tooltip shows on hover and when the
keyboard focuses the item, and its text describes the item’s input. An icon-only item already has its
aria-label: give the sl:tooltip mode="label", so a screen reader does not say it twice.
Thymeleaf source
<sl:toggle-group variant="outline" spacing="0" name="tooltipAlign" aria-label="Alignment with tooltips"> <sl:tooltip mode="label"> <sl:toggle-group-item value="left" checked aria-label="Align left"><sl:icon name="align-left"/></sl:toggle-group-item> <sl:tooltip-content>Align left</sl:tooltip-content> </sl:tooltip> <sl:tooltip mode="label"> <sl:toggle-group-item value="center" aria-label="Align center"><sl:icon name="align-center"/></sl:toggle-group-item> <sl:tooltip-content>Align center</sl:tooltip-content> </sl:tooltip> <sl:tooltip mode="label"> <sl:toggle-group-item value="right" aria-label="Align right"><sl:icon name="align-right"/></sl:toggle-group-item> <sl:tooltip-content>Align right</sl:tooltip-content> </sl:tooltip></sl:toggle-group>Rendered HTML
<div class="toggle-group" role="radiogroup" data-spacing="0" aria-label="Alignment with tooltips"> <span class="tooltip" x-data="slTooltip"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="tooltipAlign" value="left" checked aria-label="Align left"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M15 12H3"></path> <path d="M17 19H3"></path> </svg> </label> <span class="tooltip-content" role="tooltip" popover="manual" aria-hidden="true"> Align left <span class="tooltip-arrow" aria-hidden="true"></span> </span> </span> <span class="tooltip" x-data="slTooltip"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="tooltipAlign" value="center" aria-label="Align center"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M17 12H7"></path> <path d="M19 19H5"></path> </svg> </label> <span class="tooltip-content" role="tooltip" popover="manual" aria-hidden="true"> Align center <span class="tooltip-arrow" aria-hidden="true"></span> </span> </span> <span class="tooltip" x-data="slTooltip"> <label class="toggle toggle-group-item" data-variant="outline"> <input class="toggle-input" type="radio" name="tooltipAlign" value="right" aria-label="Align right"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> <path d="M21 5H3"></path> <path d="M21 12H9"></path> <path d="M21 19H7"></path> </svg> </label> <span class="tooltip-content" role="tooltip" popover="manual" aria-hidden="true"> Align right <span class="tooltip-arrow" aria-hidden="true"></span> </span> </span></div>Attributes
Section titled “Attributes”sl:toggle-group
Section titled “sl:toggle-group”| Attribute | Values | Default | Description |
|---|---|---|---|
type | single multiple | single | single: one item is on at a time, as radio buttons (the arrow keys move between them). multiple: any number, as checkboxes. |
variant | default outline | default | Visual style of the items. |
size | sm default lg | default | Size of the items. |
spacing | 0 1 2 3 4 | 2 | The gap between the items, in Tailwind's spacing steps (2 is 0.5rem). 0 joins them into one control. |
orientation | horizontal vertical | horizontal | Put the items on a row, or in a column. |
name | string | — | The name every item submits under, for a group without th:field. A single group without either gets a generated one, so its items still exclude each other. |
disabled | boolean | — | Disable every item. |
Every prop can also be set from an expression: th:type="${...}". Any other attribute passes through to the rendered element, and class is appended.
sl:toggle-group-item
Section titled “sl:toggle-group-item”sl:toggle-group-item declares no props; every attribute passes through.