Checkbox
An enhanced native <input type="checkbox"> supporting indeterminate state, checkbox groups, select-all linkage, count limits, and a card variant.
Basic Usage
Basic usage
Sizes
Three sizes (size)
size controls both the box size and the font size; set on the group it cascades to all items, while an explicit item size wins. Arbitrary pixel sizes can be set by overriding the CSS variable --_box on the host (or wait for theme-variable openings).
Indeterminate State
Indeterminate
Use it with select-all linkage scenarios (see below) to express "partially selected". Indeterminate is a visual state only — clicking still toggles the two-state value (aria-checked="mixed" stays in sync).
Disabled
Disabled
Readonly
Readonly
readonly and disabled carry distinct form semantics: focusable, reachable via Tab, value still submits, but clicks (and Space) never toggle.
Validation Status
Validation status (status)
status="error" automatically sets aria-invalid="true"; in the card variant the status color lands on the border.
Description & Label Position
Description (description) and label position (label-position)
The description attribute renders as secondary text below the label; a <span slot="description"> can distribute rich content instead (takes priority over the attribute). label-position="start" moves the text to the start side of the box (mirrors automatically in RTL).
Custom Indicator
Custom indicator (checked-icon / indeterminate-icon slots)
Slot content takes over the checked-state icon (template[slot] or a direct element both work); the unchecked state falls back to a default hollow outline, overridable via ::part(box). The indeterminate-icon slot customizes the half-checked icon, pairing well with check-all linkage.
Checkbox Group
Checkbox group
The group is controlled via value (a JSON array); each item's value acts as the option identifier. size / status / readonly set on the group cascade to items.
Button-style Multi-select (oas-toggle-group)
A "button-style" checkbox (a multi-select control with a button look where each click marks an item selected) is served here by oas-toggle-group in multiple mode (button-style multi-select group: each item toggles independently via multiple, roving-tabindex keyboard, even-width fills, etc.), while the checkbox itself keeps the standard box form. The split: use checkbox-group for standard multi-select, toggle-group for button-style multi-select.
Button-style multi-select (toggle-group)
Horizontal Group
Horizontal direction (direction)
Defaults to direction="vertical" (stacked); horizontal lays items out in a row and wraps automatically.
Data-Driven
options data channel
The options JSON attribute and declarative child elements form dual channels: when options is explicit, data-driven rendering wins (rendered internally; declarative children step aside). Fields: label / value / disabled / description / checkAll.
Count Limits
Count limits (max / min)
When max is reached, unchecked items are blocked and oas-exceed-limit fires (detail: { value, max }); when min is reached, checked items cannot be unchecked. Checked items can always be unchecked (max) and unchecked items can always be picked (min) — the limits are symmetric and one-directional.
Select All / Indeterminate Linkage
Select-all linkage (check-all)
Mark an item with check-all and the group links it automatically: clicking it toggles all items, and item changes write back the select-all item's checked/indeterminate state in real time. The select-all item never joins the group value; disabled items are skipped; combined with max, select-all truncates to the cap and shows indeterminate. No host-side glue script needed.
Card Variant
Card variant (variant=card)
variant="card" switches to a card skin: the whole block is clickable, the selected state tints the border, hover gives feedback; put titles/prices in the default slot and use description for subtext. Card items can join a group (driven by the group value as usual) or stand alone.
Events
Events (oas-change / oas-focus / oas-blur)
An item dispatches oas-change (detail: { checked, value }) plus oas-focus / oas-blur; the group dispatches oas-change (detail: { value: string[] }) and group-level oas-focus / oas-blur (moves between items do not misfire).
required
required (native validation chain)
required drives the native validation chain (form-associated): when unfilled, checkValidity() returns false (valueMissing) and native form submission is blocked; it recovers to :valid once filled.
Value Mapping
true-value / false-value customize the checked/unchecked value (strings); detail.value of oas-change returns the mapped value (falls back to the value attribute semantics when unset). Reading el.value also returns the current mapped value — useful for form submissions like 'YES' / 'NO'. Not effective inside a checkbox-group: within a group, value is fixed as the option identifier (groups collect checks by the value attribute and FormData submits the identifier); mapping attributes on group items are ignored.
true-value / false-value
tabindex Passthrough
tabindex passes through to the inner native checkbox: tabindex="-1" removes the item from the tab order (useful when an outer container owns keyboard navigation); a positive integer customizes the tab order; unset by default (default tab order preserved).
tabindex passthrough
Move focus with the Tab key: the middle item is skipped; clicking it with a mouse or touch still toggles normally.
API
oas-checkbox
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
check-all | In-group select-all marker: clicking toggles all items, item changes write back its checked/indeterminate state; the item never joins the group value (cross-component attribute read by oas-checkbox-group) | — | — |
checked | Whether checked | boolean | — |
description | Secondary text rendered below the label; a slot="description" distribution takes priority | string | — |
disabled | Disabled | boolean | — |
false-value | Mapped value when unchecked (detail.value / value getter; not added to FormData per native unchecked semantics; not effective inside a checkbox-group) | string | — |
indeterminate | Indeterminate state (visual only; clicking still toggles the two-state value; aria-checked syncs to mixed) | boolean | — |
label-position | Label position: end (default, box left / text right) / start (text left; mirrors automatically in RTL) | — | — |
readonly | Readonly: focusable and Tab-reachable, value still submits, but clicks (and Space) never toggle (distinct form semantics from disabled) | boolean | — |
required | Required marker (drives the native valueMissing validation chain; not passed through to the inner input) | boolean | — |
size | Size: small (14px) / medium (default 16px) / large (18px), box and font scale together; a group-level value cascades to items while an explicit item value wins | string | medium |
status | Validation status: error / warning / success (tints the box; error also sets host aria-invalid) | string | — |
tabindex | Forwarded to the inner native checkbox (-1 removes it from the tab order) | — | — |
true-value | Mapped value when checked: drives detail.value, the value getter and FormData submission (not effective inside a checkbox-group) | string | — |
value | Option identifier | string | boolean | on |
variant | Variant: default / card (whole block clickable, selected border tint, hover feedback) | string | — |
Events
| Event | Description |
|---|---|
oas-blur | The checkbox lost focus |
oas-change | Checked change, detail: { checked, value } |
oas-focus | The checkbox gained focus |
oas-limit-blocked | Group count-limit block signal (the group re-dispatches it as oas-exceed-limit; no such block when used standalone) |
Slots
| Name | Description |
|---|---|
| default | Label content (rich text/links allowed) |
checked-icon | Custom checked indicator (template[slot] or a direct element; unchecked falls back to the default hollow outline) |
description | Description distribution channel (takes priority over the description attribute) |
indeterminate-icon | Custom indeterminate indicator (pairs with check-all linkage) |
oas-checkbox-group
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
direction | Layout direction: vertical (default) / horizontal (row layout with wrapping) | string | vertical |
disabled | Disable the whole group (cascades to items without overriding their own explicit disabled) | boolean | — |
max | Selection cap: at the cap unchecked items gray out and block with oas-exceed-limit; checked items can still be unchecked | — | — |
min | Selection floor: at the floor checked items block unchecking; unchecked items are unaffected | — | — |
options | Data channel: JSON [{ label, value, disabled?, description?, checkAll? }]; when explicit, data-driven rendering wins over declarative children | CheckboxOption[] | string | — |
readonly | Readonly (cascades to items): focusable, no toggling | boolean | — |
size | Size (cascades to items): small / medium (default) / large | string | — |
status | Validation status (cascades to items): error / warning / success | string | — |
value | Group value (JSON string array of checked item values) | string[] | string | [] |
Property (JS property; see each row for attribute reflection)
| Property | Description | Type | Default |
|---|---|---|---|
value | Current value: array of checked value strings (equivalent to parsing the value attribute JSON) | string[] | string | — |
Events
| Event | Description |
|---|---|
oas-blur | Fired when focus leaves the group |
oas-change | Group value change, detail: { value: string[] } (includes select-all linkage and in-limit changes) |
oas-exceed-limit | Out-of-cap check attempt after max is reached, detail: { value, max } |
oas-focus | Any item inside the group gained focus (moves between items do not misfire) |
Slots
| Name | Description |
|---|---|
| default | Declarative item channel (<oas-checkbox> children; steps aside when options is explicit) |
label | Group title (rendered into the legend) |