Navy checkbox with checked and indeterminate states, a label and an optional description line. A hidden native input carries focus, Space and the screen-reader semantics; the drawn box is what the user sees. Use it alone for a yes or no question such as consent, or inside sui-checkbox-group for a set. Form-associated: posts name=value while checked.
Usage
<sui-checkbox label="Email me a copy of the invoice" name="email-copy" value="yes"></sui-checkbox>
<script type="module">
import { defineCustomElements } from "@shineui/core/loader";
import "@shineui/core/shineui.css";
defineCustomElements();
const el = document.querySelector("sui-checkbox");
el.addEventListener("suiChange", (e) => console.log(e.detail));
</script>
import { SuiCheckbox } from "@shineui/react";
import "@shineui/core/shineui.css";
export function Example() {
return <SuiCheckbox label="Email me a copy of the invoice" name="email-copy" value="yes" onSuiChange={(e) => console.log(e.detail)} />;
}
<script setup>
import { SuiCheckbox } from "@shineui/vue";
import "@shineui/core/shineui.css";
const onChange = (e) => console.log(e.detail);
</script>
<template>
<SuiCheckbox label="Email me a copy of the invoice" name="email-copy" value="yes" @sui-change="onChange" />
</template>
import { Component } from "@angular/core";
import { SuiCheckbox } from "@shineui/angular";
@Component({
standalone: true,
imports: [SuiCheckbox],
template: `<sui-checkbox label="Email me a copy of the invoice" name="email-copy" value="yes" (suiChange)="onChange($event)"></sui-checkbox>`,
})
export class Example {
onChange(e: CustomEvent) { console.log(e.detail); }
}
Basic
A hidden native input carries focus, Space toggling and the screen-reader semantics; the drawn box is what the user sees. The label element wraps both, so clicking the text toggles the box.
<sui-checkbox label="Email me a copy of the invoice" name="email-copy" value="yes"></sui-checkbox>
Indeterminate and disabled
indeterminate draws a dash and announces aria-checked="mixed", and the first toggle clears it. A description is wired through aria-describedby, and invalid is the danger border alone, for a form that draws its summary elsewhere.
<div style="display:flex;flex-direction:column;gap:12px;align-items:flex-start">
<sui-checkbox label="Keep me signed in" checked></sui-checkbox>
<sui-checkbox label="Select all" indeterminate></sui-checkbox>
<sui-checkbox label="Include voided invoices" description="Voided documents stay in the audit trail."></sui-checkbox>
<sui-checkbox label="Lock the period on close" invalid></sui-checkbox>
<sui-checkbox label="Locked by policy" disabled checked></sui-checkbox>
</div>
Sizes and unlabeled boxes
md is 18px and sm is 16px. A box with no visible label takes its accessible name from the host aria-label, which is what a table selection column needs.
<div style="display:flex;flex-direction:column;gap:12px;align-items:flex-start">
<sui-checkbox label="Send a reminder 7 days before due" size="md" checked></sui-checkbox>
<sui-checkbox label="Send a reminder on the due date" size="sm" checked></sui-checkbox>
<sui-checkbox size="sm" aria-label="Select invoice INV-1043"></sui-checkbox>
</div>
States
A consent box is a field on its own, so it draws its own message line: help sits under the box, and error replaces it, paints the danger border and sets aria-invalid. The message renders outside the label element, so clicking it does not tick the box.
<div style="display:grid;gap:16px;max-width:420px">
<sui-checkbox label="Email me a copy of the invoice" help="Sent to the billing address on the customer record."></sui-checkbox>
<sui-checkbox label="I accept the engagement letter" required help="Required before we can file."></sui-checkbox>
<sui-checkbox label="I accept the engagement letter" required error="Accept the engagement letter to continue."></sui-checkbox>
</div>
Read-only
readonly keeps the box named and in the tab order, a click or Space changes nothing, and it still posts; a disabled box posts nothing. Neither holds the form on valueMissing.
<div style="display:grid;gap:16px;max-width:420px">
<sui-checkbox label="Engagement letter accepted" name="letter" checked readonly help="Accepted on 12 Aug by the client; a new letter is a new record."></sui-checkbox>
</div>
In a form
A checked box posts name=value, where value defaults to "on", and an unchecked box posts nothing, the way a native checkbox does. A required box that is not ticked holds the form on valueMissing, and the browser names the field from its label.
<form id="cb-form" style="display:grid;gap:12px;justify-items:start;max-width:380px">
<sui-checkbox name="reminders" value="yes" label="Send payment reminders" checked></sui-checkbox>
<sui-checkbox name="attach" label="Attach the PDF" description="The invoice is attached to every email."></sui-checkbox>
<sui-checkbox name="terms" required label="I accept the deposit terms"></sui-checkbox>
<sui-button type="submit" variant="brand" label="Save settings"></sui-button>
<output id="cb-form-out" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Submit to see what posts.</output>
</form>
Moves to the box; the drawn box shows the focus ring.
Space
Toggles the box and fires suiChange; on a mixed box the first press clears the dash.
Enter
Submits the surrounding form, as a native checkbox does.
API
<sui-checkbox>
Properties
Property
Attribute
Type
Default
Description
checked
checked
boolean
false
Checked state. Mutable: the element toggles it on user input, then emits suiChange. Reflected, so sui-checkbox[checked] matches the box as it is now.
description
description
stringstring | undefined
Secondary line under the label explaining the consequence.
disabled
disabled
boolean
false
Disables the box. A disabled box posts nothing and never holds the form.
error
error
stringstring | undefined
Error message under the box; also paints the danger border and sets aria-invalid. Inside a sui-checkbox-group the group owns the message line instead.
help
help
stringstring | undefined
Help text under the box. Replaced by error when set.
indeterminate
indeterminate
boolean
false
Mixed state for select-all headers: drawn as a dash, announced as "mixed". The first toggle clears it.
invalid
invalid
boolean
false
Danger border without a message, for a form that draws its summary elsewhere.
label
label
stringstring | undefined
Visible label.
name
name
stringstring | undefined
Form control name. Reflected: the form entry is built from the content attribute.
readOnly
readonly
boolean
false
Display only: the box keeps its name and its tab stop but a click or Space changes nothing, and it still posts. Neither a read-only nor a disabled box holds the form on valueMissing.
required
required
boolean
false
Must be checked for the surrounding form to be valid, as a consent box is.
size
size
"md" | "sm"
'md'
Box size: md 18px (default), sm 16px.
value
value
string
'on'
Value posted with the form while checked; defaults to "on". Inside a sui-checkbox-group the group posts instead and this box posts nothing.
Events
Event
Detail
React
Vue
Description
suiChange
boolean
onSuiChange
@sui-change
Fires on toggle; detail is the new checked state.
Methods
Method
Signature
Description
setFocus()
setFocus() => Promise<void>
Moves keyboard focus to the (hidden) native input, as el.focus() does; the drawn box shows the focus ring.
Theming
Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.