Components
Checkbox
Checkboxes allow users to select one or more items from a set of options. See also: Checkbox field group.
---import { Checkbox } from "@opui/astro"---
<Checkbox checked name="checkbox" hideLabel>Checked</Checkbox><Checkbox name="checkbox" hideLabel>Unchecked</Checkbox><Checkbox indeterminate name="checkbox" hideLabel>Indeterminate</Checkbox><Checkbox disabled name="checkbox" hideLabel>Disabled</Checkbox><Checkbox checked disabled name="checkbox" hideLabel >Checked and disabled</Checkbox><label class="checkbox"> <input type="checkbox" checked name="checkbox" /><span class="sr-only" >Checked</span ></label><label class="checkbox"> <input type="checkbox" name="checkbox" /><span class="sr-only" >Unchecked</span ></label><label class="checkbox"> <input type="checkbox" data-indeterminate="true" name="checkbox" /><span class="sr-only" >Indeterminate</span ></label><label class="checkbox"> <input type="checkbox" disabled name="checkbox" /><span class="sr-only" >Disabled</span ></label><label class="checkbox"> <input type="checkbox" checked disabled name="checkbox" /><span class="sr-only" >Checked and disabled</span ></label>Visible label
Render the label text inside an element with a .label class. Also,
don't miss the info on label accessibility.
---import { Checkbox } from "@opui/astro"---
<Checkbox checked name="checkbox">Choice A</Checkbox><Checkbox disabled name="checkbox">Disabled</Checkbox><Checkbox checked disabled name="checkbox">Checked and disabled</Checkbox><Checkbox name="checkbox"> <span class="label" >Long text dolor amet mustache knausgaard +1, blue bottle waistcoat tbh semiotics artisan synth stumptown gastropub cornhole <a class="link" href="#visible-label">privacy policy ipsum</a ></span ></Checkbox><label class="checkbox"> <input type="checkbox" checked name="checkbox" /><span class="label" >Choice A</span ></label><label class="checkbox"> <input type="checkbox" disabled name="checkbox" /><span class="label" >Disabled</span ></label><label class="checkbox"> <input type="checkbox" checked disabled name="checkbox" /><span class="label" >Checked and disabled</span ></label><label class="checkbox"> <input type="checkbox" name="checkbox" /><span class="label"> <span class="label" >Long text dolor amet mustache knausgaard +1, blue bottle waistcoat tbh semiotics artisan synth stumptown gastropub cornhole <a class="link" href="#visible-label">privacy policy ipsum</a></span > </span></label>Label position
---import { Checkbox } from "@opui/astro"---
<Checkbox name="checkbox">Default</Checkbox><Checkbox stack name="checkbox">Stack</Checkbox><label class="checkbox"> <input type="checkbox" name="checkbox" /><span class="label">Default</span></label><label class="checkbox stack"> <input type="checkbox" name="checkbox" /><span class="label">Stack</span></label>End text
---import { Checkbox } from "@opui/astro"---
<Checkbox name="checkbox"> Default <Fragment slot="end-text">Supporting text</Fragment></Checkbox><Checkbox stack name="checkbox"> Stack <Fragment slot="end-text">Supporting text</Fragment></Checkbox><label class="checkbox"> <input type="checkbox" name="checkbox" aria-describedby="end-text-1" /><span class="label" > Default </span> <span id="end-text-1" class="end-text">Supporting text</span></label><label class="checkbox stack"> <input type="checkbox" name="checkbox" aria-describedby="end-text-2" /><span class="label" > Stack </span> <span id="end-text-2" class="end-text">Supporting text</span></label>Validation
-
Add
[required]to the<input>element to toggle required styles -
The
data-invalidattribute toggles the error styles. Make use of the end text to give extra feedback on the error.
---import { Checkbox } from "@opui/astro"---
<div class="example-row spacious"> <Checkbox required name="checkbox">Default</Checkbox> <Checkbox stack required name="checkbox">Stack</Checkbox></div><div class="example-row spacious"> <Checkbox critical checked name="checkbox"> Default <Fragment slot="end-text">Check yourself</Fragment> </Checkbox> <Checkbox stack critical name="checkbox"> Stack <Fragment slot="end-text">Before you wreck yourself</Fragment> </Checkbox></div><div class="example-row spacious"> <label class="checkbox"> <input type="checkbox" name="checkbox" required /><span class="label" >Default</span > </label> <label class="checkbox stack"> <input type="checkbox" name="checkbox" required /><span class="label" >Stack</span > </label></div><div class="example-row spacious"> <label class="checkbox" data-invalid="true"> <input type="checkbox" checked name="checkbox" aria-describedby="end-text-3" /><span class="label"> Default </span> <span id="end-text-3" class="end-text">Check yourself</span> </label> <label class="checkbox stack" data-invalid="true"> <input type="checkbox" name="checkbox" aria-describedby="end-text-4" /><span class="label" > Stack </span> <span id="end-text-4" class="end-text">Before you wreck yourself</span> </label></div>Indeterminate
Set the indeterminate prop to render a partially-selected state.
indeterminate is a JavaScript-only property on HTMLInputElement, so the component renders data-indeterminate and applies the
property at runtime.
JavaScript required
indeterminate state cannot be set with HTML or CSS alone.
The browser only exposes it as a property on HTMLInputElement, so a small script is needed to flip el.indeterminate = true after the element is in the DOM. The :indeterminate CSS pseudo-class
then matches and the dash glyph appears.
---import { Checkbox, FieldGroup, FieldLegend, FieldSet } from "@opui/astro"---
<FieldSet class="indeterminate-demo"> <FieldLegend> <Checkbox class="parent">Select all</Checkbox> </FieldLegend> <FieldGroup name="indeterminate-children-astro"> <Checkbox class="child" checked>Apples</Checkbox> <Checkbox class="child">Bananas</Checkbox> <Checkbox class="child">Cherries</Checkbox> </FieldGroup></FieldSet>
<script> function setupIndeterminateDemo() { document .querySelectorAll<HTMLElement>(".indeterminate-demo") .forEach((root) => { const parent = root.querySelector<HTMLInputElement>( '.parent input[type="checkbox"]', ) const children = Array.from( root.querySelectorAll<HTMLInputElement>( '.child input[type="checkbox"]', ), ) if (!parent || children.length === 0) return
const sync = () => { const checkedCount = children.filter((c) => c.checked).length parent.checked = checkedCount === children.length parent.indeterminate = checkedCount > 0 && checkedCount < children.length }
parent.addEventListener("change", () => { children.forEach((c) => (c.checked = parent.checked)) parent.indeterminate = false }) children.forEach((c) => c.addEventListener("change", sync)) sync() }) }
setupIndeterminateDemo() document.addEventListener("astro:after-swap", setupIndeterminateDemo)</script><script type="module"> function d() { document.querySelectorAll(".indeterminate-demo").forEach((c) => { const t = c.querySelector('.parent input[type="checkbox"]'), n = Array.from(c.querySelectorAll('.child input[type="checkbox"]')); if (!t || n.length === 0) return; const r = () => { const e = n.filter((a) => a.checked).length; ((t.checked = e === n.length), (t.indeterminate = e > 0 && e < n.length)); }; (t.addEventListener("change", () => { (n.forEach((e) => (e.checked = t.checked)), (t.indeterminate = !1)); }), n.forEach((e) => e.addEventListener("change", r)), r()); }); } d(); document.addEventListener("astro:after-swap", d);</script><fieldset class="fieldset indeterminate-demo"> <legend> <label class="checkbox parent"> <input type="checkbox" /><span class="label">Select all</span> </label> </legend> <div class="field-group" role="group"> <script type="module"> function e(t = document) { t.querySelectorAll( 'input[type="checkbox"][data-indeterminate]', ).forEach((n) => { n.indeterminate = !0; }); } function a() { (e(), document.addEventListener("astro:after-swap", () => e())); } a(); </script> <label class="checkbox child"> <input type="checkbox" checked name="indeterminate-children-astro" /><span class="label" >Apples</span > </label> <label class="checkbox child"> <input type="checkbox" name="indeterminate-children-astro" /><span class="label" >Bananas</span > </label> <label class="checkbox child"> <input type="checkbox" name="indeterminate-children-astro" /><span class="label" >Cherries</span > </label> </div></fieldset>Spread
Use the spread prop to push the label to the left and the checkbox
to the right. This is useful for full-width items like lists and menus.
---import { Checkbox } from "@opui/astro"---
<Checkbox spread> Accept Terms & Conditions <Fragment slot="end-text" >I have read and agree to the privacy policy.</Fragment ></Checkbox>
<Checkbox spread required> Required <Fragment slot="end-text">You must accept this to continue.</Fragment></Checkbox>
<Checkbox spread disabled> Disabled <Fragment slot="end-text">This checkbox is disabled.</Fragment></Checkbox>
<Checkbox spread critical> Invalid Checkbox <Fragment slot="end-text">There is an error with this checkbox.</Fragment></Checkbox><label class="checkbox spread"> <input type="checkbox" name="indeterminate-children-astro" aria-describedby="end-text-5" /><span class="label"> Accept Terms & Conditions </span> <span id="end-text-5" class="end-text" >I have read and agree to the privacy policy.</span ></label><label class="checkbox spread"> <input type="checkbox" name="indeterminate-children-astro" required aria-describedby="end-text-6" /><span class="label"> Required </span> <span id="end-text-6" class="end-text" >You must accept this to continue.</span ></label><label class="checkbox spread"> <input type="checkbox" disabled name="indeterminate-children-astro" aria-describedby="end-text-7" /><span class="label"> Disabled </span> <span id="end-text-7" class="end-text">This checkbox is disabled.</span></label><label class="checkbox spread" data-invalid="true"> <input type="checkbox" name="indeterminate-children-astro" aria-describedby="end-text-8" /><span class="label"> Invalid Checkbox </span> <span id="end-text-8" class="end-text" >There is an error with this checkbox.</span ></label>Sizes
---import { Checkbox } from "@opui/astro"---
<div class="example-row"> <Checkbox hideLabel size="small" checked name="checkbox">Label</Checkbox> <Checkbox hideLabel checked name="checkbox">Label</Checkbox> <Checkbox hideLabel size="large" checked name="checkbox">Label</Checkbox></div><div class="example-row"> <Checkbox size="small" checked name="checkbox">Small</Checkbox> <Checkbox checked name="checkbox">Default</Checkbox> <Checkbox size="large" checked name="checkbox">Large</Checkbox></div><div class="example-row"> <label class="checkbox small"> <input type="checkbox" checked name="checkbox" /><span class="sr-only" >Label</span > </label> <label class="checkbox"> <input type="checkbox" checked name="checkbox" /><span class="sr-only" >Label</span > </label> <label class="checkbox large"> <input type="checkbox" checked name="checkbox" /><span class="sr-only" >Label</span > </label></div><div class="example-row"> <label class="checkbox small"> <input type="checkbox" checked name="checkbox" /><span class="label" >Small</span > </label> <label class="checkbox"> <input type="checkbox" checked name="checkbox" /><span class="label" >Default</span > </label> <label class="checkbox large"> <input type="checkbox" checked name="checkbox" /><span class="label" >Large</span > </label></div>Field group
Use field groups to group related checkboxes.
The name prop will get passed down to each checkbox in the group.
See also: Form documentation.
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet> <FieldLegend>Legend</FieldLegend> <FieldGroup name="checkbox-group-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> </FieldSet></Form><form class="form"> <fieldset class="fieldset"> <legend>Legend</legend> <div class="field-group" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-astro" /><span class="label" >Checkbox 1</span > </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-astro" /><span class="label" >Checkbox 2</span > </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-astro" /><span class="label" >Checkbox 3</span > </label> </div> </fieldset></form>Direction
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet> <FieldLegend>Legend</FieldLegend> <FieldGroup direction="row" name="checkbox-group-direction-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> </FieldSet></Form><form class="form"> <fieldset class="fieldset"> <legend>Legend</legend> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-direction-astro" /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-direction-astro" /><span class="label" >Checkbox 2</span > </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-direction-astro" /><span class="label" >Checkbox 3</span > </label> </div> </fieldset></form>Field description
Can be placed above and below the fields.
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldDescription } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet> <FieldLegend>Legend</FieldLegend> <FieldDescription>Field description above fields</FieldDescription> <FieldGroup direction="row" name="checkbox-group-field-description-1-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> </FieldSet>
<FieldSet> <FieldLegend>Legend</FieldLegend> <FieldGroup direction="row" name="checkbox-group-field-description-2-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> <FieldDescription>Field description below fields</FieldDescription> </FieldSet></Form><form class="form"> <fieldset class="fieldset"> <legend>Legend</legend> <p class="field-description">Field description above fields</p> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-field-description-1-astro" /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-field-description-1-astro" /><span class="label">Checkbox 2</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-field-description-1-astro" /><span class="label">Checkbox 3</span> </label> </div> </fieldset> <fieldset class="fieldset"> <legend>Legend</legend> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-field-description-2-astro" /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-field-description-2-astro" /><span class="label">Checkbox 2</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-field-description-2-astro" /><span class="label">Checkbox 3</span> </label> </div> <p class="field-description">Field description below fields</p> </fieldset></form>Disabled
Attach the disabled attribute to the <fieldset> element.
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet disabled> <FieldLegend>Legend</FieldLegend> <FieldGroup direction="row" name="checkbox-group-disabled-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> </FieldSet></Form><form class="form"> <fieldset disabled class="fieldset"> <legend>Legend</legend> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-disabled-astro" /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-disabled-astro" /><span class="label" >Checkbox 2</span > </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-disabled-astro" /><span class="label" >Checkbox 3</span > </label> </div> </fieldset></form>Required
Attach the required attribute to at least one of your <input> elements.
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet> <FieldLegend>These are required!</FieldLegend> <FieldGroup direction="row" name="checkbox-group-required-astro"> <Checkbox required>Checkbox 1</Checkbox> <Checkbox required>Checkbox 2</Checkbox> <Checkbox required>Checkbox 3</Checkbox> </FieldGroup> </FieldSet></Form><form class="form"> <fieldset class="fieldset"> <legend>These are required!</legend> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" name="checkbox-group-required-astro" required /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-required-astro" required /><span class="label">Checkbox 2</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-required-astro" required /><span class="label">Checkbox 3</span> </label> </div> </fieldset></form>Validation
Attach the data-invalid attribute to your Fieldset component.
---import { Checkbox } from "@opui/astro"import { FieldSet } from "@opui/astro"import { FieldLegend } from "@opui/astro"import { FieldGroup } from "@opui/astro"import { Form } from "@opui/astro"---
<Form> <FieldSet data-invalid> <FieldLegend>Legend</FieldLegend> <FieldGroup direction="row" name="checkbox-group-validation-astro"> <Checkbox checked>Checkbox 1</Checkbox> <Checkbox>Checkbox 2</Checkbox> <Checkbox>Checkbox 3</Checkbox> </FieldGroup> <span class="end-text">Something went wrong!</span> </FieldSet></Form><form class="form"> <fieldset data-invalid="true" class="fieldset"> <legend>Legend</legend> <div class="field-group row" role="group"> <label class="checkbox"> <input type="checkbox" checked name="checkbox-group-validation-astro" /><span class="label">Checkbox 1</span> </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-validation-astro" /><span class="label" >Checkbox 2</span > </label> <label class="checkbox"> <input type="checkbox" name="checkbox-group-validation-astro" /><span class="label" >Checkbox 3</span > </label> </div> <span class="end-text">Something went wrong!</span> </fieldset></form>Accessibility
Labels
Accessible checkboxes must have a label. You can choose between three approaches:
| Approach | Usage in Checkbox component |
|---|---|
Provide a label text inside the label/role="checkbox" element
| Default |
Add a aria-label on the input element | Not used |
Have a visible label that you reference with aria-labelledby | Not used |
Keyboard support
| Key | Function |
|---|---|
| Space | When Checkbox is focused it changes its state. |
| Enter | (Optional) When Checkbox is focused it changes its state. |
Anatomy
- Container
- Input
- Label (optional)
- End text (optional)
API
Checkbox API
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | false | Input checked state. |
disabled | boolean | - | Input disabled state. |
critical | boolean | - | Input error state. |
hideLabel | boolean | - | Visually hides the label. |
indeterminate | boolean | false | Visual partial-selection state. Applied via JS at runtime; does not affect form submission. |
required | boolean | false | Input required state. |
size | "small" | "large" | - | The size of the input. |
spread | boolean | false | Spreads the label and input to opposite ends. |
stack | boolean | false | Stacks the label under the input. |
Slots
| Slot | Description |
|---|---|
default | The label text for the component. |
end-text | Optional supporting text displayed after the label. |
Field group API
| Prop | Type | Default | Description |
|---|---|---|---|
critical | boolean | false | Field group error state. |
legend | string | - | The text for the legend element. |
direction | "row" | - | The orientation of the field group. |
Browser support
See also the full browser support guide.
Installation
See also
@layer components.root { label.checkbox { --_input-size: var(--size-4);
align-items: center; color: var(--text-primary); cursor: pointer; display: inline-grid; gap: 0 var(--size-2); grid-auto-columns: auto; grid-auto-flow: column; inline-size: fit-content; line-height: 1.5; transform: translateZ(0); user-select: none;
/* Disabled */ &:has([disabled]) { cursor: not-allowed; opacity: 0.64; user-select: none;
input { cursor: not-allowed; } }
/* Required dot */ &:has(:invalid) { .label:after { color: var(--red); content: "*"; inset: 0 -0.25ex auto auto; position: absolute; } }
/* Label */ .label { color: var(--text-primary); font-size: var(--font-size-05); grid-column: 2; grid-row: 1; position: relative; padding-inline: 0 1ex; }
/* End text */ :where(.end-text) { color: var(--text-muted); font-size: var(--font-size-0); grid-column: 2; grid-row: 2; line-height: 1.5; z-index: 1; }
/* Spread layout */ &.spread { align-items: center; column-gap: var(--size-4); grid-auto-flow: unset; grid-template-columns: 1fr auto; inline-size: 100%;
.label { font-weight: 600; grid-column: 1; grid-row: 1; inline-size: fit-content; }
input { grid-column: 2; grid-row: 1; }
:where(.end-text) { grid-column: 1; grid-row: 2; } }
/* Stacked layout */ &.stack { justify-items: center; grid-auto-columns: unset;
.label { grid-column: 1/-1; grid-row: 2; margin-block-start: var(--size-1); padding-inline: 1ex;
/* Required dot */ &::after { inset: 0 -0.25ex auto auto; } }
.end-text { grid-column: 1/-1; grid-row: 3; } }
/* Input */ input[type="checkbox"] { --_input-size: var(--size-4);
appearance: none; aspect-ratio: 1; background-color: var(--surface-default); block-size: var(--_input-size); border-radius: var(--radius-1); border: 1px solid var(--border-color); box-sizing: border-box; cursor: pointer; display: grid; font-size: var(--_input-size); inline-size: var(--_input-size); margin: 0; padding: 0; place-items: center; position: relative;
&:checked, &:indeterminate { background-color: var(--primary); border-color: var(--primary); }
/* Checkmark */ &::after { background-color: var(--primary-contrast); clip-path: polygon(15% 52%, 40% 77%, 85% 32%, 75% 22%, 40% 57%, 25% 42%); content: ""; inset: 0; opacity: 0; position: absolute; }
&:checked::after, &:indeterminate::after { opacity: 1; }
/* Indeterminate dash */ &:indeterminate::after { clip-path: polygon(20% 45%, 80% 45%, 80% 55%, 20% 55%); }
&::before { --highlight-size: 175%; } }
/* Sizes */ &.small { input[type="checkbox"] { --_input-size: var(--size-3); } }
&.large { input[type="checkbox"] { --_input-size: var(--size-5); } }
/* Validation */ &[data-invalid], &:has(:user-invalid) { --palette-source: oklch(0.58 0.21 var(--hue-red));
:where(.end-text) { color: var(--primary); } }
/* Touch devices */ @media (pointer: coarse) { input { --_input-size: var(--size-4); } }
@media (forced-colors: active) { input { border: 1px solid CanvasText;
&:checked, &:indeterminate { background-color: SelectedItem; border-color: SelectedItem;
&::after { background-color: SelectedItemText; } } } } }}@layer components.extended {
/* Form */ :where(.form) { display: grid; gap: var(--size-8);
hr { margin-block: 0; } }
/* Fieldset */ :where(.fieldset) { all: unset; border: 0; border-radius: 0; display: grid; gap: var(--size-1); margin: 0; min-inline-size: 0; padding: 0;
/* Legend */ :where(legend, .legend) { all: unset; color: var(--text-primary); font-weight: 600; margin-block-end: var(--size-3); padding: 0;
&:has(+ :where(.field-description)) { margin-block-end: 0; } }
/* Field description / supporting text */ :where(.field-description) { color: var(--text-muted); font-size: var(--font-size-05); line-height: var(--font-lineheight-3);
&:has(+ *) { margin-block-end: var(--size-3); } }
/* End text */ :where(.end-text) { color: var(--text-muted); font-size: var(--font-size-0); line-height: var(--font-lineheight-3); }
&:has(.text-field.row) { row-gap: var(--size-7); }
/* Disabled */ &[disabled] { opacity: 0.64; user-select: none;
input, label, .label { cursor: not-allowed; } }
/* Error / validation */ &[data-invalid] { :where(.end-text) { color: var(--primary); }
:where(.checkbox, .radio, .switch) { --palette-source: oklch(0.58 0.21 var(--hue-red));
:where(.end-text) { color: var(--primary); } }
:where(.switch) { input { border-radius: var(--radius-round); outline: 2px solid var(--primary); } } }
/* Required */ &:has(:invalid) { :where(legend, .legend) { padding-inline-end: 1ex; position: relative;
&::after { color: var(--red); content: "*"; inset: 0 -0.25ex auto auto; position: absolute; } } } }
/* Field group */ :where(.field-group) { display: flex; flex-direction: column; gap: var(--size-4);
/* If it only has checkboxes, radios, or switches */ &:has(> :where(.checkbox, .radio, .switch)):not(:has(> :not(.checkbox, .radio, .switch))) { gap: var(--size-2); }
/* If it only has buttons */ &:has(.button):not(:has(*:not(.button))) { align-items: center; flex-direction: row; gap: var(--size-2);
/* If it's not preceeded by an hr */ &:not(hr + &) { margin-block-start: var(--size-4); } }
&+& { margin-block-start: var(--size-5); }
/* Directions */ &.row { flex-direction: row; flex-wrap: wrap;
&:has(> :where(.checkbox, .radio, .switch)) { gap: var(--size-4); } } }}