HyCheckbox
Usage examples on this page are written for Lit / plain HTML (
<hy-checkbox>). The same component ships asHyCheckboxin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A form-associated tri-state checkbox component that supports unchecked, checked, and indeterminate states. Provides comprehensive form integration via the ElementInternals API, accessibility features, and customizable styling.
Key Behavioral Model
This checkbox implements a clear separation between user interactions and programmatic control:
Limited to 2 states: Only toggle between
unchecked↔checkedNever access indeterminate: Indeterminate state is invisible to users
Standard behavior: Follows native HTML checkbox conventions
Predictable UX: Users get consistent toggle behavior regardless of settings
Full 3-state access: Can set
unchecked,checked, orindeterminateMethod-controlled: Use
setState(),setIndeterminate(),toggle(), etc.Flexible behavior: Respects
allowIndeterminatesetting for methods liketoggle()Event tracking: All changes include
reasonfield ('user' | 'programmatic')
Form Integration
This component implements the Form-Associated Custom Elements API, allowing it to participate in form submission just like native checkboxes. The checkbox's value will be included in FormData when checked and the form is submitted. Indeterminate state is treated as unchecked for form purposes.
Keyboard Navigation
- Space key: Toggles between
unchecked↔checked(standard behavior) - Tab: Moves focus to/from the checkbox
- Enter: No effect (standard checkbox behavior - doesn't change state)
- Indeterminate access: Only via programmatic methods like
setState('indeterminate', 'programmatic')
State Management Philosophy
The component treats indeterminate as a display-only state for users:
- Users see it visually but can't directly set it
- User interactions "exit" indeterminate by going to checked first
- Applications control indeterminate programmatically for complex UI patterns
- Clear event tracking helps distinguish user intent from application logic
Common Use Cases
Examples
Simple Two-State Preferences
<form>
<hy-checkbox
name="notifications"
value="enabled"
label="Enable notifications"
allow-indeterminate="false"
>
</hy-checkbox>
<button type="submit">Save</button>
</form>Form Validation with Required Fields
<form>
<hy-checkbox
name="terms"
value="accepted"
label="I accept the terms"
required
variant="error"
allow-indeterminate="false"
>
</hy-checkbox>
<button type="submit">Submit</button>
</form>Event Handling
## API
### Properties
| Property | Attribute | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `state` | `state` | `'unchecked' \| 'checked' \| 'indeterminate'` | `'unchecked'` | — |
| `label` | `label` | `string` | `''` | — |
| `helpText` | `help-text` | `string` | `''` | — |
| `topLabel` | `top-label` | `string` | `''` | — |
| `disabled` | `disabled` | `boolean` | `false` | — |
| `required` | `required` | `boolean` | `false` | — |
| `name` | `name` | `string` | `''` | — |
| `value` | `value` | `string` | `''` | — |
| `variant` | `variant` | `'default' \| 'error'` | `'default'` | — |
| `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | — |
| `ariaDescribedby` | `aria-describedby` | `string` | `''` | — |
| `allowIndeterminate` | `allow-indeterminate` | `boolean` | `true` | — |
| `checkboxId` | `checkbox-id` | `string` | `''` | — |
| `helperTextId` | `helper-text-id` | `string` | `''` | — |
| `topLabelId` | `top-label-id` | `string` | `''` | — |
| `autofocus` | `autofocus` | `boolean` | `false` | Marks this checkbox as the auto-focus target. Read by `hy-dialog` (and other overlay containers) on `show` to choose initial focus. Also focuses on first connect when used outside an overlay, mirroring native HTML `autofocus` but routed through JS so SSR'd HTML doesn't pull focus during hydration. |
| `checked` | `checked` | `boolean` | — | — |
| `indeterminate` | `indeterminate` | `boolean` | — | — |
| `form` | — | `HTMLFormElement \| null` | — | — |
| `validity` | — | `ValidityState` | — | — |
| `validationMessage` | — | `string` | — | — |
### Events
| Event | Detail | Description |
| --- | --- | --- |
| `change` | — | Fired when state changes. Detail: { state: CheckboxState, checked: boolean, indeterminate: boolean, value: string, reason: StateChangeReason } |
| `input` | — | Standard form input event |
### Slots
| Slot | Description |
| --- | --- |
| `top-label` | Content above the checkbox |
| `help-text` | Content below the checkbox |
| `check-icon` | Custom icon for the checked state (overrides the default check icon) |
| `indeterminate-icon` | Custom icon for the indeterminate state (overrides the default minus icon) |
### CSS Parts
| Part | Description |
| --- | --- |
| `base` | The checkbox's base wrapper element |
### CSS Custom Properties
| Property | Description |
| --- | --- |
| `--hy-checkbox-text-transform` | Text transform for checkbox label |
| `--hy-checkbox-font-family` | Font family override for checkbox label |
| `--hy-checkbox-focus-ring-width` | Focus ring width override |
| `--hy-checkbox-border-rest` | Border of the unchecked box. Default: `var(--hy-border-default-rest)` (rest stays own-role; checked escalates to the indicator fill) |
| `--hy-checkbox-indicator-fill` | Background of the checked/indeterminate indicator **Default:** `var(--hy-background-brand-rest)` |
| `--hy-checkbox-indicator-fill-danger` | Background of the checked/indeterminate indicator in error state **Default:** `var(--hy-background-danger-rest)` |
| `--hy-checkbox-height-sm` | Outer container min-height for small size variant. Per-component override in the form-control height contract (see `.claude/rules/control-heights.md`). The indicator stays at indicator-size inside; the host floors to form-row baseline (Position A) so checkboxes align with selects/inputs in inline form rows. **Default:** `var(--hy-control-height-sm)` |
| `--hy-checkbox-height-md` | Outer container min-height for medium size variant. **Default:** `var(--hy-control-height-md)` |
| `--hy-checkbox-height-lg` | Outer container min-height for large size variant. **Default:** `var(--hy-control-height-lg)` |
| `--hy-checkbox-hover-duration` | Transition duration for hover and focus state feedback |
| `--hy-checkbox-hover-easing` | Transition easing for hover and focus state feedback |