Users can check a checkbox by tapping anywhere on it. The label is also part of the hitbox and ensures proper support in assistive technologies, improving usability and accessibility. To uncheck it, it may be tapped again. There is also a disabled variant of the checkbox that cannot be clicked or tapped.
Indeterminate
An indeterminate state indicates that a checkbox's value is neither fully checked nor unchecked, typically used in nested lists to show that only some sub-items are selected. It serves as a visual "mixed" status, ensuring the parent element accurately reflects the partial selection of its children without implying a checked or default state.
In a nested list, there are three specific states possible: Indeterminate (only some sub-elements are selected), Checked (all sub-elements are selected), and Unchecked (no sub-elements are selected).
When
Fitting
The checkbox is 1.5rem high and 1.5rem wide. The label is set to fit-content by default, but it can be overwritten to fill-parent. Note, that the whole line is interactive in this case.
The checkbox has a mandatory label which can be placed left or right with a small gap to the checkbox. Ideally, there should be a 24px gap between checkboxes if they are placed vertically or horizontally.
Use the checkbox when multiple options can be selected (multiple selection) or a standalone option can be checked. When only one option can be selected from a list use radio buttons (single selection).
Use the checkbox when a separate interaction is needed to confirm a choice, such as "Speichern" or "Bestätigen", or when multiple options can be selected simultaneously as part of a larger form.
Use the switch for immediate actions, such as toggling a setting on or off. The action happens the moment the user interacts with it.
Checkbox: confirmed with a button
Weiter
Switch: takes effect at once
Livesingle selection on desktop and mobileHTML
<p class="demo-label">Checkbox: confirmed with a button</p>
<oc-checkbox-v2><input type="checkbox" checked aria-label="oc-auto"><label slot="label">Ich möchte den OTTO-Newsletter erhalten.</label></oc-checkbox-v2>
<oc-button-v1 variant="primary">Weiter</oc-button-v1>
<p class="demo-label">Switch: takes effect at once</p>
<oc-switch-v3><input type="checkbox" checked aria-label="oc-auto"><label slot="label">OTTO-Newsletter erhalten</label></oc-switch-v3>
Do not use switches for lists consisting of multiple options. Instead, use checkboxes. Checkboxes imply that the items are related and take up less visual space than switches.
CautionOnly nest checkboxes if you are using the indeterminate state.DoUse the actual label of the checkbox.
This is the only way to ensure consistent behavior and layout.
LiveDoHTML
<oc-checkbox-v2 width-behavior="fit"><input type="checkbox" aria-label="oc-auto"><label slot="label">Auch der Text ist klickbar</label></oc-checkbox-v2>
Newsletter
Don'tUse custom text as a label. The spacing may be off, and proper user interaction (i.e., a hitbox spanning the entire element and interactive states) cannot be ensured.
Content Guidelines
DoUse short, precise labels to describe the options.Don'tUse overly descriptive labels to describe the options.
Accessibility
For information on accessibility, refer to the technical documentation.
Only the latest version (v2) is allowed for generation. Older versions are kept for reference and are deprecated.
Overview (v2)
Checkbox
The checkbox component lets users select one or more options while keeping the label and validation messaging aligned with OTTO design tokens.
It pairs a slotted input element with optional hint and validation slots so that you can keep native form semantics.
This component is configurable, allowing you to tailor its features and appearance to your specific needs.
To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.
Usage guidelines
Before integrating the checkbox component into your project, make sure you have correctly installed the OTTO components package.
Look through the variations page for examples of possible component variations.
Here, you can discover both common and specific variations that address different use cases.
This component has visual overflow.
It extends beyond its bounding box and is clipped by parent containers with overflow: hidden.
Ensure the parent container has sufficient padding to accommodate the component's full visual area.
Accessibility
The checkbox component relies on the attributes applied to the slotted input, so always provide aria-label or an associated <label> element and propagate required, disabled, and checked states through the native control.
Reference the built-in accessibility features guide for keyboard expectations and screen-reader behavior.
Configuration (v2)
Checkbox configuration
Configure the checkbox component with the controls below and see the changes live in the preview canvas.
Click the Show code button within the preview canvas to see the source code for the current component configuration.
Interactive configurator (Storybook controls); every option is listed in the API section of this file.
Migration (v2)
Migration from checkbox v1 to v2
The oc-checkbox component has been updated from oc-checkbox-v1 to oc-checkbox-v2.
This migration guide provides step-by-step instructions to update your project to the latest version.
Now contains the native <input type="checkbox"> element
—
hint
New slot for hint text
—
error
New slot for validation message
Removed attributes
The following attributes have been removed and should now be set on the native <input> element:
v1 Attribute
v2 Equivalent
Notes
checked
Set checked on the <input> element
Moved to native input
disabled
Set disabled on the <input> element
Moved to native input
name
Set name on the <input> element
Moved to native input
value
Set value on the <input> element
Moved to native input
required
Set required on the <input> element
Moved to native input
oc-aria-label
Set aria-label on the <input> element
Renamed to standard attribute
hint
Use the hint slot
Moved to slot
validation-message
Use the error slot
Moved to slot
variant
The error state is now automatically applied when the error slot has content
Auto-applied based on slot
How to migrate
The main change is that v2 uses a native <input type="checkbox"> element in the default slot instead of managing the checkbox state internally.
This provides better accessibility, form integration, and native event support.
The Checkbox component allows users to select one or more options from a set, with properties for state, styling, and accessibility, and a slot for setting the Checkbox label text.
Attributes / properties
Attribute
Type
Default
Required
Description
variant
"default" | "error"
"default"
no
Sets the main styling variant of the checkbox. Can be one of: "default", "error".
value
string
"on"
no
Sets the initial value of a ticked checkbox to the provided value for form processing. If this attribute is not specified, the default value of value="on" is used as the submitted data.
hint
string
undefined
no
Provides additional information related to the checkbox below the element.
validation-message
string
undefined
no
Provides a validation message related to the checkbox below the element.
Implicitly sets the checkbox to the error state.
checked
boolean
false
no
Indicates whether the checkbox is checked. When enabled, the checkbox is initially ticked.
Accessible in CSS via the custom-state mixin.
disabled
boolean
false
no
Indicates whether the checkbox is disabled, preventing user interaction and input.
required
boolean
false
no
Indicates whether the input is required for screen readers. Doesn't prevent form submission on its own.
fit-content
boolean
no
Sets the width behavior of the checkbox.
name
string
undefined
no
Sets the name tag to identify the checkbox when submitting a form. Mandatory if single-selection is set to true.
label-placement
"left" | "right"
"right"
no
Sets the placement direction of the label provided via the default slot relative to the checkbox.
oc-aria-label
string
undefined
no
Sets the ARIA label of the checkbox.
Slots
Slot
Required
Description
default
yes
Sets the text content for the checkbox label to provide a brief description of the input field.
Events
Event
Detail type
Description
oc-property-change
OcCheckboxV1Events["oc-property-change"]
Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.
Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount
{ component: string; }
Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
API v2
Checkbox v2 API
API: <oc-checkbox-v2> (CheckboxV2)
The Checkbox component allows users to select one or more options from a set.
Provides attributes for state, styling, validation, accessibility, and slots for the label, input element, hints, and errors.
Attributes / properties
Attribute
Type
Default
Required
Description
size
"50" | "100"
"100"
no
The size of the checkbox.
width-behavior
"fill" | "fit"
"fill"
no
Defines the width behavior of the checkbox component. - "fill": The component expands to fill the available width. - "fit": The component width fits its content.
label-placement
"left" | "right"
"right"
no
The placement direction of the label provided via the default slot relative to the checkbox indicator.
Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount
{ component: string; }
Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
Variations (v2)
Variations
Listed below are the most common variations of the checkbox component as well as specific component variations for different use cases.
You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.
Displays an error state with a hint and error message.
Args: hintSlot=<span slot='hint'>This is a hint message.</span>, errorSlot=<span slot='error'>This is an error message.</span>, defaultSlot=<input type="checkbox" aria-label="oc-auto" />
This is a hint message.This is an error message.
HTML
<oc-checkbox-v2>
<label slot="label">my label</label>
<span slot='hint'>This is a hint message.</span>
<span slot='error'>This is an error message.</span>
<input type="checkbox" aria-label="oc-auto" />
</oc-checkbox-v2>
The checkbox component allows users to select one or more options from a set, with properties for state, styling, and accessibility, and a slot for setting the checkbox label text.
The checkbox component offers a variety of styling variants such as default and error.
This component is configurable, allowing you to tailor its features and appearance to your specific needs.
To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.
Usage guidelines
Before integrating the checkbox component into your project, make sure you have correctly installed the OTTO components package.
Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.
Layout considerations
This component has visual overflow.
It extends beyond its bounding box and is clipped by parent containers with overflow: hidden.
Ensure the parent container has sufficient padding to accommodate the component's full visual area.
If the checkbox component is used in a form, pressing Enter while focused on the checkbox triggers the submit action immediately (implicit submit) if an oc-button component or a normal HTML button with the type submit is also present in the form.
Use oc-aria-label
To make the checkbox recognizable for screen readers, use the oc-aria-label attribute to provide clear and descriptive context information.
See the general accessibility documentation for guidance on using oc-aria-label, including how it works with link and masked link behavior.
V1/Configuration (v1, deprecated, not for generation)
Checkbox configuration
Configure the checkbox component with the controls below and see the changes live in the preview canvas.
Click the Show code button within the preview canvas to see the source code for the current component configuration.
V1/Variations (v1, deprecated, not for generation)
Variations
Listed below are the most common variations of the checkbox component as well as specific component variations for different use cases.
You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.
The Demo form showcases a form with multiple checkboxes, a reset button to uncheck all checkboxes, and a submit button.
<form novalidate>
<fieldset class="oc-mb-150">
<legend>Marke*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="brand" value="Samsung">Samsung</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="LG">LG</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Philips">Philips</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Sony">Sony</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Hisense">Hisense</oc-checkbox-v1>
</oc-form-group-v1>
</fieldset>
<fieldset class="oc-mb-150">
<legend>Größe*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="size" value="S">S</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="M">M</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="L">L</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="XL">XL</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="XXL">XXL</oc-checkbox-v1>
</oc-form-group-v1>
</fieldset>
<fieldset class="oc-mb-150">
<legend>Lorem*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="lorem" value="1"
>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet.</oc-checkbox-v1
>
<oc-checkbox-v1 name="lorem" value="2"
>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et
dolore magna aliquyam erat, sed diam voluptua.</oc-checkbox-v1
>
<oc-checkbox-v1 name="lorem" value="3"
>Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</oc-checkbox-v1
>
</oc-form-group-v1>
</fieldset>
<div style="display: flex; gap: 16px">
<oc-button-v1 variant="secondary" type="reset">Reset</oc-button-v1>
<oc-button-v1 type="submit">Submit</oc-button-v1>
</div>
</form>
<script>
(() => {
const [form] = document.getElementsByTagName("form");
const [group1, group2, group3] = document.getElementsByTagName("oc-form-group-v1");
form.addEventListener("change", async () => {
// wait for the next microtask to get the updated checked state
await new Promise((resolve) => setTimeout(resolve));
let formData = new FormData(form);
if (formData.has("brand")) group1.validationMessage = "";
if (formData.has("size")) group2.validationMessage = "";
if (formData.has("lorem")) group3.validationMessage = "";
});
form.addEventListener("submit", (ev) => {
let formData = new FormData(form);
group1.validationMessage = formData.has("brand") ? "" : "Please select a brand.";
group2.validationMessage = formData.has("size") ? "" : "Please select a size.";
group3.validationMessage = formData.has("lorem") ? "" : "Please select a lorem.";
if (formData.has("brand") && formData.has("size") && formData.has("lorem")) {
let data = "";
formData.forEach((value, key) => (data += key + "=" + value + "\\n"));
console.log(data);
alert("sending:\\n" + data);
}
ev.preventDefault();
});
})();
</script>
Story source (TypeScript, verbatim from Storybook)
{
name: "Demo form",
parameters: {
controls: {
disabled: true
}
},
argTypes: hideControlsBadge(Metadata),
render() {
return html`
<form novalidate>
<fieldset class="oc-mb-150">
<legend>Marke*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="brand" value="Samsung">Samsung</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="LG">LG</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Philips">Philips</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Sony">Sony</oc-checkbox-v1>
<oc-checkbox-v1 name="brand" value="Hisense">Hisense</oc-checkbox-v1>
</oc-form-group-v1>
</fieldset>
<fieldset class="oc-mb-150">
<legend>Größe*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="size" value="S">S</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="M">M</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="L">L</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="XL">XL</oc-checkbox-v1>
<oc-checkbox-v1 name="size" value="XXL">XXL</oc-checkbox-v1>
</oc-form-group-v1>
</fieldset>
<fieldset class="oc-mb-150">
<legend>Lorem*</legend>
<oc-form-group-v1 orientation="horizontal" flex-behavior="shrink">
<oc-checkbox-v1 name="lorem" value="1"
>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet.</oc-checkbox-v1
>
<oc-checkbox-v1 name="lorem" value="2"
>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et
dolore magna aliquyam erat, sed diam voluptua.</oc-checkbox-v1
>
<oc-checkbox-v1 name="lorem" value="3"
>Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</oc-checkbox-v1
>
</oc-form-group-v1>
</fieldset>
<div style="display: flex; gap: 16px">
<oc-button-v1 variant="secondary" type="reset">Reset</oc-button-v1>
<oc-button-v1 type="submit">Submit</oc-button-v1>
</div>
</form>
<script>
(() => {
const [form] = document.getElementsByTagName("form");
const [group1, group2, group3] = document.getElementsByTagName("oc-form-group-v1");
form.addEventListener("change", async () => {
// wait for the next microtask to get the updated checked state
await new Promise((resolve) => setTimeout(resolve));
let formData = new FormData(form);
if (formData.has("brand")) group1.validationMessage = "";
if (formData.has("size")) group2.validationMessage = "";
if (formData.has("lorem")) group3.validationMessage = "";
});
form.addEventListener("submit", (ev) => {
let formData = new FormData(form);
group1.validationMessage = formData.has("brand") ? "" : "Please select a brand.";
group2.validationMessage = formData.has("size") ? "" : "Please select a size.";
group3.validationMessage = formData.has("lorem") ? "" : "Please select a lorem.";
if (formData.has("brand") && formData.has("size") && formData.has("lorem")) {
let data = "";
formData.forEach((value, key) => (data += key + "=" + value + "\\n"));
console.log(data);
alert("sending:\\n" + data);
}
ev.preventDefault();
});
})();
</script>
`;
}
}