Components
Checkbox
See also: Checkbox field group.
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <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 ></template><!--[--><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-sr-only" ><!--[-->Checked<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-sr-only" ><!--[-->Unchecked<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" data-indeterminate="true" name="checkbox" /><span class="ui-sr-only" ><!--[-->Indeterminate<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" disabled name="checkbox" /><span class="ui-sr-only" ><!--[-->Disabled<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" disabled name="checkbox" /><span class="ui-sr-only" ><!--[-->Checked and disabled<!--]--></span ><!----></label><!--]-->Visible label
Render the label text inside an element with a .ui-label class.
Also, don't miss the info on label accessibility.
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <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 >Long text dolor amet mustache knausgaard +1, blue bottle waistcoat tbh semiotics artisan synth stumptown gastropub cornhole <a class="ui-link" href="#visible-label">privacy policy ipsum</a></span > </Checkbox></template><!--[--><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[-->Choice A<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" disabled name="checkbox" /><span class="ui-label" ><!--[-->Disabled<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" disabled name="checkbox" /><span class="ui-label" ><!--[-->Checked and disabled<!--]--></span ><!----></label><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[--><span >Long text dolor amet mustache knausgaard +1, blue bottle waistcoat tbh semiotics artisan synth stumptown gastropub cornhole <a class="ui-link" href="#visible-label">privacy policy ipsum</a></span ><!--]--></span ><!----></label><!--]-->Label position
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <Checkbox name="checkbox">Default</Checkbox> <Checkbox stack name="checkbox">Stack</Checkbox></template><!--[--><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[-->Default<!--]--></span ><!----></label><label class="ui-checkbox ui-stack" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[-->Stack<!--]--></span ><!----></label><!--]-->End text
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <Checkbox name="checkbox"> Default <template #end-text>Supporting text</template> </Checkbox> <Checkbox stack name="checkbox"> Stack <template #end-text>Supporting text</template> </Checkbox></template><!--[--><label class="ui-checkbox" ><input type="checkbox" name="checkbox" aria-describedby="s3-0" /><span class="ui-label" ><!--[--> Default <!--]--></span ><span id="s3-0" class="ui-end-text" ><!--[-->Supporting text<!--]--></span ></label><label class="ui-checkbox ui-stack" ><input type="checkbox" name="checkbox" aria-describedby="s3-1" /><span class="ui-label" ><!--[--> Stack <!--]--></span ><span id="s3-1" class="ui-end-text" ><!--[-->Supporting text<!--]--></span ></label><!--]-->Validation
-
Add the
requiredattribute on the component. It is forwarded to the underlying<input>. -
Use the
errorprop to toggle invalid styles. It rendersdata-invalidon the root element. Make use of the end text to give extra feedback on the error.
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <div class="example-row ui-spacious"> <Checkbox required name="checkbox">Default</Checkbox> <Checkbox stack required name="checkbox">Stack</Checkbox> </div> <div class="example-row ui-spacious"> <Checkbox error checked name="checkbox"> Default <template #end-text>Check yourself</template> </Checkbox> <Checkbox stack error name="checkbox"> Stack <template #end-text>Before you wreck yourself</template> </Checkbox> </div></template><!--[--><div class="example-row ui-spacious"> <label class="ui-checkbox" ><input type="checkbox" required name="checkbox" /><span class="ui-label" ><!--[-->Default<!--]--></span ><!----></label ><label class="ui-checkbox ui-stack" ><input type="checkbox" required name="checkbox" /><span class="ui-label" ><!--[-->Stack<!--]--></span ><!----></label ></div><div class="example-row ui-spacious"> <label class="ui-checkbox" data-invalid="true" ><input type="checkbox" name="checkbox" aria-describedby="s4-2" /><span class="ui-label" ><!--[--> Default <!--]--></span ><span id="s4-2" class="ui-end-text" ><!--[-->Check yourself<!--]--></span ></label ><label class="ui-checkbox ui-stack" data-invalid="true" ><input type="checkbox" name="checkbox" aria-describedby="s4-3" /><span class="ui-label" ><!--[--> Stack <!--]--></span ><span id="s4-3" class="ui-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.
<script setup lang="ts">import { computed, ref } from "vue"import { Checkbox, FieldGroup, FieldLegend, FieldSet } from "opui-css/vue"
const items = ["Apples", "Bananas", "Cherries"]const checked = ref([true, false, false])
const allChecked = computed(() => checked.value.every(Boolean))const someChecked = computed(() => checked.value.some(Boolean))const indeterminate = computed(() => someChecked.value && !allChecked.value)
function toggleAll() { const next = !allChecked.value checked.value = checked.value.map(() => next)}</script>
<template> <FieldSet> <FieldLegend> <Checkbox :model-value="allChecked" :indeterminate="indeterminate" @update:model-value="toggleAll" >Select all</Checkbox > </FieldLegend> <FieldGroup name="indeterminate-children"> <Checkbox v-for="(item, index) in items" :key="item" v-model="checked[index]" >{{ item }}</Checkbox > </FieldGroup> </FieldSet></template><fieldset class="ui-fieldset"> <!--[--> <legend class=""> <!--[--><label class="ui-checkbox" ><input type="checkbox" data-indeterminate="true" /><span class="ui-label" ><!--[-->Select all<!--]--></span ><!----></label ><!--]--> </legend> <div class="ui-field-group" role="group"> <!--[--><!--[--><label class="ui-checkbox" ><input type="checkbox" checked /><span class="ui-label" ><!--[-->Apples<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Bananas<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-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.
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <Checkbox spread> Accept Terms & Conditions <template #end-text>I have read and agree to the privacy policy.</template> </Checkbox>
<Checkbox spread required> Required <template #end-text>You must accept this to continue.</template> </Checkbox>
<Checkbox spread disabled> Disabled <template #end-text>This checkbox is disabled.</template> </Checkbox>
<Checkbox spread error> Invalid Checkbox <template #end-text>There is an error with this checkbox.</template> </Checkbox></template><!--[--><label class="ui-checkbox ui-spread" ><input type="checkbox" aria-describedby="s6-0" /><span class="ui-label" ><!--[--> Accept Terms & Conditions <!--]--></span ><span id="s6-0" class="ui-end-text" ><!--[-->I have read and agree to the privacy policy.<!--]--></span ></label><label class="ui-checkbox ui-spread" ><input type="checkbox" required aria-describedby="s6-1" /><span class="ui-label" ><!--[--> Required <!--]--></span ><span id="s6-1" class="ui-end-text" ><!--[-->You must accept this to continue.<!--]--></span ></label><label class="ui-checkbox ui-spread" ><input type="checkbox" disabled aria-describedby="s6-2" /><span class="ui-label" ><!--[--> Disabled <!--]--></span ><span id="s6-2" class="ui-end-text" ><!--[-->This checkbox is disabled.<!--]--></span ></label><label class="ui-checkbox ui-spread" data-invalid="true" ><input type="checkbox" aria-describedby="s6-3" /><span class="ui-label" ><!--[--> Invalid Checkbox <!--]--></span ><span id="s6-3" class="ui-end-text" ><!--[-->There is an error with this checkbox.<!--]--></span ></label><!--]-->Sizes
<script setup lang="ts">import { Checkbox } from "opui-css/vue"</script>
<template> <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></template><!--[--><div class="example-row"> <label class="ui-checkbox ui-small" ><input type="checkbox" name="checkbox" /><span class="ui-sr-only" ><!--[-->Label<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-sr-only" ><!--[-->Label<!--]--></span ><!----></label ><label class="ui-checkbox ui-large" ><input type="checkbox" name="checkbox" /><span class="ui-sr-only" ><!--[-->Label<!--]--></span ><!----></label ></div><div class="example-row"> <label class="ui-checkbox ui-small" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[-->Small<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" name="checkbox" /><span class="ui-label" ><!--[-->Default<!--]--></span ><!----></label ><label class="ui-checkbox ui-large" ><input type="checkbox" name="checkbox" /><span class="ui-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.
<script setup lang="ts">import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"</script>
<template> <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></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset"> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <div class="ui-field-group" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <!--]--> </fieldset> <!--]--></form>Direction
<script setup lang="ts">import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"</script>
<template> <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></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset"> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <!--]--> </fieldset> <!--]--></form>Field description
Can be placed above and below the fields.
<script setup lang="ts">import { Checkbox, FieldDescription, FieldGroup, FieldLegend, FieldSet, Form,} from "opui-css/vue"</script>
<template> <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></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset"> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <p class="ui-field-description"> <!--[-->Field description above fields<!--]--> </p> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <!--]--> </fieldset> <fieldset class="ui-fieldset"> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <p class="ui-field-description"> <!--[-->Field description below fields<!--]--> </p> <!--]--> </fieldset> <!--]--></form>Disabled
Attach the disabled attribute to the <fieldset> element.
<script setup lang="ts">import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"</script>
<template> <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></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset" disabled> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <!--]--> </fieldset> <!--]--></form>Required
Attach the required attribute to at least one of your <input> elements.
<script setup lang="ts">import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"</script>
<template> <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></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset"> <!--[--> <legend class=""><!--[-->These are required!<!--]--></legend> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" required /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" required /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" required /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <!--]--> </fieldset> <!--]--></form>Validation
Attach the data-invalid attribute to your FieldSet component.
<script setup lang="ts">import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"</script>
<template> <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="ui-end-text">Something went wrong!</span> </FieldSet> </Form></template><form class="ui-form"> <!--[--> <fieldset class="ui-fieldset" data-invalid> <!--[--> <legend class=""><!--[-->Legend<!--]--></legend> <div class="ui-field-group ui-row" role="group"> <!--[--><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 1<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 2<!--]--></span ><!----></label ><label class="ui-checkbox" ><input type="checkbox" /><span class="ui-label" ><!--[-->Checkbox 3<!--]--></span ><!----></label ><!--]--> </div> <span class="ui-end-text">Something went wrong!</span ><!--]--> </fieldset> <!--]--></form>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. |
- Container
- Input
- Label (optional)
- End text (optional)
API
Checkbox API
Field group API
Browser support
See also the full browser support guide.
Installation
See also
@layer components.root { label.ui-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) { .ui-label:after { color: var(--red); content: "*"; inset: 0 -0.25ex auto auto; position: absolute; } }
/* Label */ .ui-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(.ui-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 */ &.ui-spread { align-items: center; column-gap: var(--size-4); grid-auto-flow: unset; grid-template-columns: 1fr auto; inline-size: 100%;
.ui-label { font-weight: 600; grid-column: 1; grid-row: 1; inline-size: fit-content; }
input { grid-column: 2; grid-row: 1; }
:where(.ui-end-text) { grid-column: 1; grid-row: 2; } }
/* Stacked layout */ &.ui-stack { justify-items: center; grid-auto-columns: unset;
.ui-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; } }
.ui-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 */ &.ui-small { input[type="checkbox"] { --_input-size: var(--size-3); } }
&.ui-large { input[type="checkbox"] { --_input-size: var(--size-5); } }
/* Validation */ &[data-invalid], &:has(:user-invalid) { --primary: var(--critical);
:where(.ui-end-text) { color: var(--critical); } }
/* 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(.ui-form) { display: grid; gap: var(--size-8);
hr { margin-block: 0; } }
/* Fieldset */ :where(.ui-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, .ui-legend) { all: unset; color: var(--text-primary); font-weight: 600; margin-block-end: var(--size-3); padding: 0;
&:has(+ :where(.ui-field-description)) { margin-block-end: 0; } }
/* Field description / supporting text */ :where(.ui-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(.ui-end-text) { color: var(--text-muted); font-size: var(--font-size-0); line-height: var(--font-lineheight-3); }
&:has(.ui-text-field.ui-row) { row-gap: var(--size-7); }
/* Disabled */ &[disabled] { opacity: 0.64; user-select: none;
input, label, .ui-label { cursor: not-allowed; } }
/* Error / validation */ &[data-invalid] { :where(.ui-end-text) { color: var(--critical); }
:where(.ui-checkbox, .ui-radio, .ui-switch) { --primary: var(--critical);
:where(.ui-end-text) { color: var(--critical); } }
:where(.ui-switch) { input { border-radius: var(--radius-round); outline: 2px solid var(--critical); } } }
/* Required */ &:has(:invalid) { :where(legend, .ui-legend) { padding-inline-end: 1ex; position: relative;
&::after { color: var(--red); content: "*"; inset: 0 -0.25ex auto auto; position: absolute; } } } }
/* Field group */ :where(.ui-field-group) { display: flex; flex-direction: column; gap: var(--size-4);
/* If it only has checkboxes, radios, or switches */ &:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)):not( :has(> :not(.ui-checkbox, .ui-radio, .ui-switch)) ) { gap: var(--size-2); }
/* If it only has buttons */ &:has(.ui-button):not(:has(*:not(.ui-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 */ &.ui-row { flex-direction: row; flex-wrap: wrap;
&:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)) { gap: var(--size-4); } } }}