Core · Form fields
Choice
Pick from options the reader can see: checkbox, radio, switch and select.
A select sits in .luz-field as in Inputs.
Checkbox
A box the reader ticks for a yes or no, or for any of several independent options.
Code
Copy the markup
A native checkbox inside .luz-check-item, with its label beside it; .luz-check-group stacks several:
<div class="luz-check-group" role="group" aria-labelledby="notify-label">
<div class="luz-check-item"><input type="checkbox" id="notify-email" checked><label for="notify-email">Email</label></div>
<div class="luz-check-item"><input type="checkbox" id="notify-push"><label for="notify-push">Push</label></div>
</div>
Variants and options
checked: a filled box with a check mark.disabled: faded, skipped by Tab, not sent.required: the browser stops the form until it is ticked.
How it works
A native <input> with appearance: none, redrawn by components/form.css. The label is tied to it with for and id, so a click on the text ticks the box.
Without JavaScript
Every box ticks, unticks and submits with its form.
Keyboard and ARIA
- Tab moves between the boxes; Space ticks or unticks the one with focus.
- Give a group of boxes a name that a screen reader reads before the first one, as the label does in the markup above.
Contrast and focus are in the Design tab.
Design
When to use
Use a checkbox when the reader may choose none, one or several options.
- A yes or no that is saved with a button: "Email me about new releases".
- A list where any number of options may apply.
When not to use
Do not use a checkbox for one choice out of several, or for a setting that applies at once.
- One choice out of several: radio buttons.
- A setting that takes effect the moment it changes: a switch.
Do and don't
Writing the content
- Write the label so that ticked means yes: "Email me about new releases".
- One line, in sentence case, with no full stop.
- No negatives: "Do not email me" makes the reader untick to say yes.
Contrast and focus
Shared with the other choice controls: contrast and focus of choice.
Tokens it uses
Shared with the other choice controls: tokens of choice.
Keyboard and ARIA are in the Code tab.
Radio
Round buttons for one option out of a few, every option in view.
Code
Copy the markup
Radios with the same name are one choice. A <fieldset> with a <legend> asks the question:
<fieldset class="luz-fieldset">
<legend>Plan</legend>
<div class="luz-check-group">
<div class="luz-check-item"><input type="radio" name="plan" id="plan-free" checked><label for="plan-free">Free</label></div>
<div class="luz-check-item"><input type="radio" name="plan" id="plan-team"><label for="plan-team">Team</label></div>
</div>
</fieldset>
Variants and options
checked: the option chosen at the start. Only one option of a group can be.requiredon one radio: the browser stops the form until the group has an answer.disabled: skipped by Tab, not sent.
How it works
A native <input type="radio"> with appearance: none, redrawn by components/form.css: a ring that fills with a dot in the brand colour. The browser makes the group of the radios that share a name.
Without JavaScript
Every group works and submits its chosen value with the form.
Keyboard and ARIA
- Tab moves into the group, to the chosen option or the first, and out of it. Arrow keys move the choice within the group. Space chooses the focused option.
- The legend names the group, and each label names its option.
Contrast and focus are in the Design tab.
Design
When to use
Use radio buttons when the reader chooses exactly one of a few options and should see them all.
- Six options or fewer: a plan, a size, a delivery method.
- Choose the option most readers want to start, or none when the choice must be conscious.
When not to use
Do not use radio buttons for a long list, or for answers that are not exclusive.
- More than six options: a select.
- Any number of options: checkboxes. A single yes or no: a checkbox or a switch.
Do and don't
Writing the content
- The legend is the question or a noun: "Plan", "Delivery method".
- Options are short and parallel, in sentence case, in an order the reader can predict.
- Say what each option means in its label, not in a hint beside it.
Contrast and focus
Shared with the other choice controls: contrast and focus of choice.
Tokens it uses
Shared with the other choice controls: tokens of choice.
Keyboard and ARIA are in the Code tab.
Switch
A switch for a setting that is on or off and takes effect at once.
Code
Copy the markup
A checkbox with role="switch" inside a <label>; the track and the thumb are drawn after it:
<label class="luz-toggle">
<input class="luz-toggle__input" type="checkbox" role="switch">
<span class="luz-toggle__track" aria-hidden="true"><span class="luz-toggle__thumb"></span></span>
<span class="luz-toggle__label">Weekly digest</span>
</label>
Variants and options
checked: on. The track fills with the brand colour and the thumb moves to the end.disabled: a faded track, skipped by Tab, not sent.
How it works
A native checkbox, hidden but still focusable, with role="switch". .luz-toggle draws the track and the thumb; the thumb moves the other way in right-to-left text, and forced colors redraw both with system colors. LUZ ships no script: a change takes effect when your own script acts on it.
Without JavaScript
The switch turns on and off and submits with its form. Applying the change at once is your script's job.
Keyboard and ARIA
- Tab moves focus to the switch; Space turns it on or off.
- The label is the name;
role="switch"tells the browser it is on or off, not ticked.
Contrast and focus are in the Design tab.
Design
When to use
Use a switch for a setting that applies the moment it changes, with no button to confirm.
- A preference, a mode or a feature that is on or off.
- Name the setting in the label, so that on means it is active.
When not to use
Do not use a switch for a choice that waits for a button.
- In a form that is sent with a button: a checkbox.
- One choice out of several: radio buttons.
Do and don't
Writing the content
- Name the setting: "Public profile", "Weekly digest".
- Do not write On or Off in the label: the switch shows it.
- No negatives: "Hide my profile" makes on mean off.
Contrast and focus
Shared with the other choice controls: contrast and focus of choice.
Tokens it uses
Shared with the other choice controls: tokens of choice.
Keyboard and ARIA are in the Code tab.
Select
A native drop-down list for one option out of a long list, the closed box styled by tokens.
Code
Copy the markup
A bare select needs no class. .luz-select adds the styled open list, where the browser can draw one:
<div class="luz-field">
<label class="luz-field__label" for="country">Country</label>
<select class="luz-select" id="country" name="country">
<option value="">Select a country</option>
<option value="de">Germany</option>
<option value="es">Spain</option>
</select>
</div>
Variants and options
aria-invalid="true": a thicker danger border; pair it with the error text.disabled: disabled text and a dashed border.multiple,size: a list that stays open, with a full border and no arrow.<optgroup label>: a labelled set of options.
How it works
A native <select> styled by components/select.css in two layers: the closed box in every browser, and the open list inside @supports (appearance: base-select). The arrow follows the text colour and moves to the left in right-to-left text.
Without JavaScript
Nothing changes: the select is a native element and LUZ adds no script to it.
Keyboard and ARIA
- Tab moves to the select. Enter or Space opens the list, Escape closes it, Up and Down move through the options.
- Give it a visible
<label for>and no role. For an error, setaria-invalid="true"and pointaria-describedbyat the text.
Contrast and focus are in the Design tab.
Design
When to use
Use a select when the reader must choose one option from a long list they already know the answer to.
- A country, a year, a time zone: more than six options, one answer.
- The options are short and the reader can scan them in order.
When not to use
A select hides the options until the reader opens it, and some people find that hard. The six-option rule is LUZ's own.
- Six options or fewer: radio buttons, so every option stays in view.
- Several answers: checkboxes. Never build your own listbox from
<div>elements.
Do and don't
Writing the content
- The label says what to choose, as a noun: "Country", not "Please select".
- The first option is a prompt with an empty value, so a required field is not answered by default.
- Sentence case, in an order the reader can predict, such as alphabetical.
Contrast and focus
Shared with the other choice controls: contrast and focus of choice.
Tokens it uses
Shared with the other choice controls: tokens of choice.
Keyboard and ARIA are in the Code tab.
Contrast and focus of choice
The label is primary text on the page; the box has to be seen against it.
| Part | Colour on background | Light | Dark | High contrast | Needs |
|---|---|---|---|---|---|
Label | --luz-text-primary on --luz-surface-page | 15.8:1 | 15.1:1 | 21.0:1 | 4.5:1 |
Box border and switch track, off | --luz-outline on --luz-surface-page | 4.3:1 | 3.6:1 | 21.0:1 | 3:1 |
Checked box and switch track, on | --luz-brand-fill on --luz-surface-page | 5.6:1 | 3.5:1 | 14.1:1 | 3:1 |
Check mark and switch thumb, on | --luz-text-on-fill on --luz-brand-fill | 6.0:1 | 4.9:1 | 14.1:1 | 3:1 |
Switch thumb, off | --luz-text-on-fill on --luz-outline | 4.6:1 | 4.8:1 | 21.0:1 | 3:1 |
Chosen radio, ring and dot | --luz-brand-primary on --luz-surface-page | 5.6:1 | 7.7:1 | 14.1:1 | 3:1 |
Select text and arrow | --luz-text-primary on --luz-input-bg | 16.5:1 | 14.0:1 | 21.0:1 | 4.5:1 |
Select border | --luz-input-border on --luz-surface-page | 3.7:1 | 4.2:1 | 21.0:1 | 3:1 |
Select error border | --luz-color-danger on --luz-input-bg | 5.5:1 | 10.8:1 | 9.3:1 | 3:1 |
Open list text | --luz-text-primary on --luz-surface | 16.5:1 | 14.0:1 | 21.0:1 | 4.5:1 |
Option under the pointer | --luz-text-primary on --luz-surface-muted | 15.8:1 | 15.1:1 | 20.1:1 | 4.5:1 |
Focus ring | --luz-focus-ring on --luz-surface-page | 5.6:1 | 7.7:1 | 21.0:1 | 3:1 |
Measured from the token values of each mode, rounded down. Needs is the WCAG 2.2 AA minimum: 4.5:1 for text, 3:1 for focus rings, borders and icons.
- Focus: a 2 px
--luz-focus-ringoutline, 2 px outside the box, the switch track or the select. - Not colour alone: a ticked box is filled and has a check mark, a chosen radio has a dot and the switch thumb moves.
- Target: the whole row, box and label, takes the click.
Tokens of choice
The 27 tokens that these controls' rules read, by token family. Each family links to its page, with the values in every mode.
- Color
--luz-brand-fill,--luz-brand-primary,--luz-color-danger,--luz-focus-ring,--luz-input-bg,--luz-input-border,--luz-outline,--luz-surface,--luz-surface-muted,--luz-text-disabled,--luz-text-on-fill,--luz-text-primary- Spacing and sizing
--luz-control-lg,--luz-control-md,--luz-space-2xs,--luz-space-3xs,--luz-space-sm,--luz-space-xl,--luz-space-xs- Typography
--luz-font-sans,--luz-text-control,--luz-text-md- Radius
--luz-radius-full,--luz-radius-md,--luz-radius-sm- Shadows
--luz-shadow-md- Motion
--luz-duration-fast
Known issues
The open list of a select looks different in each browser and system. This is intended.
- The closed box is the same everywhere; the list that opens from it is drawn by the browser or the operating system.
- Where
appearance: base-selectis supported (Chrome and Edge 135 and later, Safari 27 and later), the list takes LUZ's colors, shape and spacing. Firefox shows its own. - On phones, the system's own picker opens, and LUZ cannot style it.