Segmented control

Use it when the options are few and short and the choice changes the current view or text: the form of address in a reply ("du / ihr / Sie"), "Liste / Kalender", "Woche / Monat". Underneath it is a radio group, so it also works inside forms.

For longer option texts, more than four options or options that need a hint, use a radio choice group instead.

The legend names the choice. In toolbars where the context is obvious it may be visually hidden (hideLegend) — it is still read by screen readers.

Examples

Form of address

Anrede in der Antwort
Data
render({
  "id": "register",
  "legend": "Anrede in der Antwort",
  "value": "du",
  "options": [
    {
      "value": "du",
      "label": "du"
    },
    {
      "value": "ihr",
      "label": "ihr"
    },
    {
      "value": "sie",
      "label": "Sie"
    }
  ]
})
Markup
<fieldset class="fieldset">
<legend id="register-legend">Anrede in der Antwort</legend>
<div class="segmented" role="radiogroup" aria-labelledby="register-legend"><label><input type="radio" id="register-1" name="register" value="du" checked><span>du</span></label><label><input type="radio" id="register-2" name="register" value="ihr"><span>ihr</span></label><label><input type="radio" id="register-3" name="register" value="sie"><span>Sie</span></label></div>
</fieldset>

View switch, legend hidden, full width

Ansicht
Data
render({
  "id": "view",
  "legend": "Ansicht",
  "hideLegend": true,
  "block": true,
  "value": "calendar",
  "options": [
    {
      "value": "list",
      "label": "Liste"
    },
    {
      "value": "calendar",
      "label": "Kalender"
    }
  ]
})
Markup
<fieldset class="fieldset">
<legend id="view-legend" class="u-visually-hidden">Ansicht</legend>
<div class="segmented" role="radiogroup" aria-labelledby="view-legend" data-block><label><input type="radio" id="view-1" name="view" value="list"><span>Liste</span></label><label><input type="radio" id="view-2" name="view" value="calendar" checked><span>Kalender</span></label></div>
</fieldset>

Data contract

What render(data) accepts — validated against this JSON Schema in development and tests. Unknown fields are rejected. The same schema is in components.json.

FieldTypeRequiredDefaultDescription
idstringrequired—Id prefix: {id}-legend and option ids {id}-1, {id}-2, … Must be unique on the page.
pattern ^[A-Za-z][\w-]*$
legendstringrequired—What is being chosen ("Anrede in der Antwort").
min 1 chars
hideLegendbooleanoptionalfalseHide the legend visually (kept for screen readers).
namestringoptional—Form field name of the radios; defaults to id.
valuestringoptional—Value of the selected option. Without it, the first option is selected — a segmented control always has a selection.
blockbooleanoptionalfalseStretch to the full width of its container (e.g. on phones).
optionsarray of objectsrequired—2–4 options in display order.
min 2 items · max 4 items
options[].valuestringrequired—Submitted value.
options[].labelstringrequired—Short visible text (one or two words).
min 1 chars · max 20 chars
JSON Schema
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "legend",
    "options"
  ],
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^[A-Za-z][\\w-]*$",
      "description": "Id prefix: `{id}-legend` and option ids `{id}-1`, `{id}-2`, … Must be unique on the page."
    },
    "legend": {
      "type": "string",
      "minLength": 1,
      "description": "What is being chosen (\"Anrede in der Antwort\")."
    },
    "hideLegend": {
      "type": "boolean",
      "default": false,
      "description": "Hide the legend visually (kept for screen readers)."
    },
    "name": {
      "type": "string",
      "description": "Form field name of the radios; defaults to `id`."
    },
    "value": {
      "type": "string",
      "description": "Value of the selected option. Without it, the first option is selected — a segmented control always has a selection."
    },
    "block": {
      "type": "boolean",
      "default": false,
      "description": "Stretch to the full width of its container (e.g. on phones)."
    },
    "options": {
      "type": "array",
      "minItems": 2,
      "maxItems": 4,
      "description": "2–4 options in display order.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "value",
          "label"
        ],
        "properties": {
          "value": {
            "type": "string",
            "description": "Submitted value."
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "description": "Short visible text (one or two words)."
          }
        }
      }
    }
  }
}

Markup & states

Root: div (inside fieldset.fieldset).segmented — usable without render() by writing the markup directly.

Attributes

AttributeValuesDefaultDescription
role="radiogroup"——Group role, named by the legend (aria-labelledby="{id}-legend").
data-block——Full width.

Parts

PartDescription
labelOne segment; wraps the radio and its text.
input[type="radio"]Transparent radio covering the segment (keeps native keyboard behaviour).
spanVisible segment text.

States

StateDescription
input:checked + spanRaised surface, full-contrast text.
input:focus-visible + spanFocus ring on the segment.

Accessibility

  • Native radios: Tab enters the group, arrow keys change the selection.
  • The group is named by its legend, even when the legend is visually hidden.
  • Segment text is short but complete — no icon-only segments without accessible text.

Guidance

DoKeep labels to one or two words.
DoAlways have exactly one option selected.
Don'tDon't use it for actions ("Speichern / Abbrechen") — those are buttons.
Don'tDon't use more than 4 segments; switch to a radio group or select.

Related: Checkbox / radio group · Tabs