Checkbox
Native checkbox with explicit label association, help text, and error messaging.
Examples
Default preview
Native checkbox only: no custom role. The inline SVG check is revealed by the checked peer state so it remains
visible in forced-colors mode. Indeterminate is deliberately not part of the API (tenet 10); consumers who need it
should copy the component and add the native el.indeterminate = true behavior themselves.
Default + help text
Monthly product notes and design-system updates.
Required before creating an account.
Error + disabled
Accept the privacy policy before continuing.
This setting cannot be changed by your role.
1<div class="space-y-8">
2 <p class="text-muted-foreground text-sm">
3 Native checkbox only: no custom role. The inline SVG check is revealed by the checked peer state so it remains
4 visible in forced-colors mode. Indeterminate is deliberately not part of the API (tenet 10); consumers who need it
5 should copy the component and add the native <code>el.indeterminate = true</code> behavior themselves.
6 </p>
7
8 <section class="space-y-4">
9 {{ partial:docs/components/label content="Default + help text" }}
10 <div class="grid gap-4 md:grid-cols-2">
11 {{ partial:components/forms/checkbox id="newsletter" name="newsletter" value="yes" label="Send me the editorial newsletter" }}
12 {{ slot:help }}Monthly product notes and design-system updates.{{ /slot:help }}
13 {{ /partial:components/forms/checkbox }}
14
15 {{ partial:components/forms/checkbox id="terms" name="terms" value="accepted" label="I agree to the terms" checked="true" }}
16 {{ slot:help }}Required before creating an account.{{ /slot:help }}
17 {{ /partial:components/forms/checkbox }}
18 </div>
19 </section>
20
21 <section class="space-y-4">
22 {{ partial:docs/components/label content="Error + disabled" }}
23 <div class="grid gap-4 md:grid-cols-2">
24 {{ partial:components/forms/checkbox id="privacy" name="privacy" value="accepted" label="I accept the privacy policy" error="true" }}
25 {{ slot:error }}Accept the privacy policy before continuing.{{ /slot:error }}
26 {{ /partial:components/forms/checkbox }}
27
28 {{ partial:components/forms/checkbox id="locked" name="locked" value="yes" label="Managed by organization policy" disabled="true" checked="true" }}
29 {{ slot:help }}This setting cannot be changed by your role.{{ /slot:help }}
30 {{ /partial:components/forms/checkbox }}
31 </div>
32 </section>
33</div>
<div class="space-y-8">
<p class="text-muted-foreground text-sm">
Native checkbox only: no custom role. The inline SVG check is revealed by the checked peer state so it remains
visible in forced-colors mode. Indeterminate is deliberately not part of the API (tenet 10); consumers who need it
should copy the component and add the native <code>el.indeterminate = true</code> behavior themselves.
</p>
<section class="space-y-4">
{{ partial:docs/components/label content="Default + help text" }}
<div class="grid gap-4 md:grid-cols-2">
{{ partial:components/forms/checkbox id="newsletter" name="newsletter" value="yes" label="Send me the editorial newsletter" }}
{{ slot:help }}Monthly product notes and design-system updates.{{ /slot:help }}
{{ /partial:components/forms/checkbox }}
{{ partial:components/forms/checkbox id="terms" name="terms" value="accepted" label="I agree to the terms" checked="true" }}
{{ slot:help }}Required before creating an account.{{ /slot:help }}
{{ /partial:components/forms/checkbox }}
</div>
</section>
<section class="space-y-4">
{{ partial:docs/components/label content="Error + disabled" }}
<div class="grid gap-4 md:grid-cols-2">
{{ partial:components/forms/checkbox id="privacy" name="privacy" value="accepted" label="I accept the privacy policy" error="true" }}
{{ slot:error }}Accept the privacy policy before continuing.{{ /slot:error }}
{{ /partial:components/forms/checkbox }}
{{ partial:components/forms/checkbox id="locked" name="locked" value="yes" label="Managed by organization policy" disabled="true" checked="true" }}
{{ slot:help }}This setting cannot be changed by your role.{{ /slot:help }}
{{ /partial:components/forms/checkbox }}
</div>
</section>
</div>
Props
| Name | Type | Default | Description |
|---|---|---|---|
id
|
string
|
|
Checkbox id used by the label and described-by wiring (falls back to name/value) |
name
|
string
|
|
Name attribute used for form submissions |
value
|
string
|
|
Value attribute used for form submissions |
label
|
string
|
|
Option label text |
checked
|
boolean
|
false
|
Checked state |
disabled
|
boolean
|
false
|
Disabled state |
error
|
boolean
|
false
|
Enables destructive visual state and aria-invalid |
class
|
string
|
|
Additional classes merged via tw_merge (root element only) |
Source
1{{#
2 @name Checkbox
3 @desc Native checkbox with explicit label association, help text, and error messaging.
4 @param id string - Checkbox id used by the label and described-by wiring (falls back to name/value)
5 @param name string - Name attribute used for form submissions
6 @param value string - Value attribute used for form submissions
7 @param label string - Option label text
8 @param checked boolean [false] - Checked state
9 @param disabled boolean [false] - Disabled state
10 @param error boolean [false] - Enables destructive visual state and aria-invalid
11 @param class string - Additional classes merged via tw_merge (root element only)
12 @slot help - Help text rendered below the checkbox
13 @slot error - Error message rendered below the checkbox and referenced by aria-describedby
14#}}
15{{ _help_slot = slot:help }}
16{{ _error_slot = slot:error }}
17{{ _field_id = id ?? '' }}
18{{ if !_field_id }}
19 {{ if name }}
20 {{ _field_id = name }}
21 {{ if value }}
22 {{ _field_id = '{name}-{value}' }}
23 {{ /if }}
24 {{ else }}
25 {{ _field_id = 'checkbox' }}
26 {{ /if }}
27{{ /if }}
28{{ _describedby = '' }}
29{{ if _field_id }}
30 {{ if _error_slot }}
31 {{ _describedby = '{_field_id}-error' }}
32 {{ elseif _help_slot }}
33 {{ _describedby = '{_field_id}-help' }}
34 {{ /if }}
35{{ /if }}
36{{ _root_classes = 'space-y-1 {class}'
37 | tw_merge }}
38{{ _checkbox_classes = 'peer border-foreground checked:bg-foreground aria-invalid:border-destructive focus-visible:border-focus-text focus-visible:outline-focus disabled:border-muted-foreground disabled:bg-muted size-5 shrink-0 appearance-none border-2 bg-transparent focus-visible:outline focus-visible:outline-4 disabled:cursor-not-allowed'
39 | tw_merge }}
40{{ _label_classes = 'text-foreground text-sm'
41 | tw_merge }}
42{{ if disabled }}
43 {{ _label_classes = 'text-muted-foreground text-sm'
44 | tw_merge }}
45{{ /if }}
46<div class="{{ _root_classes }}">
47 <div class="flex items-start gap-3">
48 <span class="relative mt-0.5 flex size-5 shrink-0 items-center justify-center">
49 <input
50 class="{{ _checkbox_classes }}"
51 type="checkbox"
52 {{ if name }}name="{{ name }}"{{ /if }}
53 {{ if value }}value="{{ value }}"{{ /if }}
54 id="{{ _field_id }}"
55 {{ if checked }}checked{{ /if }}
56 {{ if disabled }}disabled{{ /if }}
57 {{ if error }}aria-invalid="true"{{ /if }}
58 {{ if _describedby }}aria-describedby="{{ _describedby }}"{{ /if }}
59 />
60 <span
61 class="text-background peer-disabled:text-muted-foreground pointer-events-none absolute inset-0 hidden items-center justify-center peer-checked:flex"
62 aria-hidden="true"
63 >
64 {{ svg src="icons/check" class="size-4 fill-current" }}
65 </span>
66 </span>
67 <label class="{{ _label_classes }}" for="{{ _field_id }}">
68 {{ label }}
69 </label>
70 </div>
71 {{ if _error_slot }}
72 <p class="text-destructive text-sm font-bold" id="{{ _field_id }}-error">
73 {{ _error_slot }}
74 </p>
75 {{ elseif _help_slot }}
76 <p class="text-muted-foreground text-sm" id="{{ _field_id }}-help">
77 {{ _help_slot }}
78 </p>
79 {{ /if }}
80</div>
{{#
@name Checkbox
@desc Native checkbox with explicit label association, help text, and error messaging.
@param id string - Checkbox id used by the label and described-by wiring (falls back to name/value)
@param name string - Name attribute used for form submissions
@param value string - Value attribute used for form submissions
@param label string - Option label text
@param checked boolean [false] - Checked state
@param disabled boolean [false] - Disabled state
@param error boolean [false] - Enables destructive visual state and aria-invalid
@param class string - Additional classes merged via tw_merge (root element only)
@slot help - Help text rendered below the checkbox
@slot error - Error message rendered below the checkbox and referenced by aria-describedby
#}}
{{ _help_slot = slot:help }}
{{ _error_slot = slot:error }}
{{ _field_id = id ?? '' }}
{{ if !_field_id }}
{{ if name }}
{{ _field_id = name }}
{{ if value }}
{{ _field_id = '{name}-{value}' }}
{{ /if }}
{{ else }}
{{ _field_id = 'checkbox' }}
{{ /if }}
{{ /if }}
{{ _describedby = '' }}
{{ if _field_id }}
{{ if _error_slot }}
{{ _describedby = '{_field_id}-error' }}
{{ elseif _help_slot }}
{{ _describedby = '{_field_id}-help' }}
{{ /if }}
{{ /if }}
{{ _root_classes = 'space-y-1 {class}'
| tw_merge }}
{{ _checkbox_classes = 'peer border-foreground checked:bg-foreground aria-invalid:border-destructive focus-visible:border-focus-text focus-visible:outline-focus disabled:border-muted-foreground disabled:bg-muted size-5 shrink-0 appearance-none border-2 bg-transparent focus-visible:outline focus-visible:outline-4 disabled:cursor-not-allowed'
| tw_merge }}
{{ _label_classes = 'text-foreground text-sm'
| tw_merge }}
{{ if disabled }}
{{ _label_classes = 'text-muted-foreground text-sm'
| tw_merge }}
{{ /if }}
<div class="{{ _root_classes }}">
<div class="flex items-start gap-3">
<span class="relative mt-0.5 flex size-5 shrink-0 items-center justify-center">
<input
class="{{ _checkbox_classes }}"
type="checkbox"
{{ if name }}name="{{ name }}"{{ /if }}
{{ if value }}value="{{ value }}"{{ /if }}
id="{{ _field_id }}"
{{ if checked }}checked{{ /if }}
{{ if disabled }}disabled{{ /if }}
{{ if error }}aria-invalid="true"{{ /if }}
{{ if _describedby }}aria-describedby="{{ _describedby }}"{{ /if }}
/>
<span
class="text-background peer-disabled:text-muted-foreground pointer-events-none absolute inset-0 hidden items-center justify-center peer-checked:flex"
aria-hidden="true"
>
{{ svg src="icons/check" class="size-4 fill-current" }}
</span>
</span>
<label class="{{ _label_classes }}" for="{{ _field_id }}">
{{ label }}
</label>
</div>
{{ if _error_slot }}
<p class="text-destructive text-sm font-bold" id="{{ _field_id }}-error">
{{ _error_slot }}
</p>
{{ elseif _help_slot }}
<p class="text-muted-foreground text-sm" id="{{ _field_id }}-help">
{{ _help_slot }}
</p>
{{ /if }}
</div>
Dependencies
Packages
marcorieser/tailwind-merge-statamic
1composer require marcorieser/tailwind-merge-statamic
composer require marcorieser/tailwind-merge-statamic
Internal dependencies
- Slots: help, error