Kern GitHub

Toggle

Native checkbox rendered as a switch with explicit label association, help text, and error messaging.

Examples

Default preview

Toggle is a native checkbox with role="switch": it submits a form value, toggles with Space, and needs no JavaScript. The visible thumb is a peer-controlled sibling with a real border so the state remains visible in forced-colors mode where background fills may disappear.

Default + help text

Send account and workflow notifications.

Receive occasional product updates.

Error + disabled

Accept the terms before continuing.

This setting cannot be changed by your role.

Form value

When checked, the submitted form data includes email_updates=1.

1<div class="space-y-8">
2 <p class="text-muted-foreground text-sm">
3 Toggle is a native checkbox with <code>role="switch"</code>: it submits a form value, toggles with Space, and
4 needs no JavaScript. The visible thumb is a peer-controlled sibling with a real border so the state remains
5 visible in forced-colors mode where background fills may disappear.
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/toggle id="notifications" name="notifications" value="enabled" label="Notifications" }}
12 {{ slot:help }}Send account and workflow notifications.{{ /slot:help }}
13 {{ /partial:components/forms/toggle }}
14
15 {{ partial:components/forms/toggle id="marketing" name="marketing" value="yes" label="Marketing emails" checked="true" }}
16 {{ slot:help }}Receive occasional product updates.{{ /slot:help }}
17 {{ /partial:components/forms/toggle }}
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/toggle id="terms-switch" name="terms_switch" value="accepted" label="Accept terms" error="true" }}
25 {{ slot:error }}Accept the terms before continuing.{{ /slot:error }}
26 {{ /partial:components/forms/toggle }}
27
28 {{ partial:components/forms/toggle id="policy-switch" name="policy_switch" value="locked" 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/toggle }}
31 </div>
32 </section>
33
34 <section class="space-y-4">
35 {{ partial:docs/components/label content="Form value" }}
36 <form class="space-y-3" action="/" method="get">
37 {{ partial:components/forms/toggle id="email-updates" name="email_updates" value="1" label="Email updates" checked="true" }}
38 {{ slot:help }}When checked, the submitted form data includes <code>email_updates=1</code>.{{ /slot:help }}
39 {{ /partial:components/forms/toggle }}
40 {{ partial:components/primitives/button label="Example submit" type="submit" size="sm" /}}
41 </form>
42 </section>
43</div>

Props

Name Type Default Description
id string Toggle 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 Switch 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 Toggle
3 @desc Native checkbox rendered as a switch with explicit label association, help text, and error messaging.
4 @param id string - Toggle 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 - Switch 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 toggle
13 @slot error - Error message rendered below the toggle 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 = 'toggle' }}
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{{ _toggle_classes = 'peer border-foreground bg-background checked:border-primary checked:bg-primary aria-invalid:border-destructive focus-visible:border-focus-text focus-visible:outline-focus disabled:border-muted-foreground disabled:bg-muted h-6 w-10 shrink-0 appearance-none border-2 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-center gap-3">
48 <span class="relative flex h-6 w-10 shrink-0 items-center">
49 <input
50 class="{{ _toggle_classes }}"
51 type="checkbox"
52 role="switch"
53 {{ if name }}name="{{ name }}"{{ /if }}
54 {{ if value }}value="{{ value }}"{{ /if }}
55 id="{{ _field_id }}"
56 {{ if checked }}checked{{ /if }}
57 {{ if disabled }}disabled{{ /if }}
58 {{ if error }}aria-invalid="true"{{ /if }}
59 {{ if _describedby }}aria-describedby="{{ _describedby }}"{{ /if }}
60 />
61 <span
62 class="bg-foreground border-foreground peer-checked:bg-primary-foreground peer-checked:border-primary-foreground peer-disabled:bg-muted-foreground peer-disabled:border-muted-foreground pointer-events-none absolute top-1 left-1 size-4 border-2 transition-transform peer-checked:translate-x-4"
63 aria-hidden="true"
64 ></span>
65 </span>
66 <label class="{{ _label_classes }}" for="{{ _field_id }}">
67 {{ label }}
68 </label>
69 </div>
70 {{ if _error_slot }}
71 <p class="text-destructive text-sm font-bold" id="{{ _field_id }}-error">
72 {{ _error_slot }}
73 </p>
74 {{ elseif _help_slot }}
75 <p class="text-muted-foreground text-sm" id="{{ _field_id }}-help">
76 {{ _help_slot }}
77 </p>
78 {{ /if }}
79</div>

Dependencies

Packages

marcorieser/tailwind-merge-statamic

1composer require marcorieser/tailwind-merge-statamic

Internal dependencies

  • Slots: help, error