Checkbox
A styled, accessible checkbox built on a real <input type="checkbox"> — kept in the DOM
(visually hidden over a custom box) so keyboard, focus, and native form submission work for free.
The accent color and :focus-visible ring are driven by the ori-color token; invalid sets
aria-invalid; disabled is the native attribute.
The examples are organised by layer: the class reference is the standalone
@oriui/css layer, and the Framework API is the @oriui/vue component. Every
example is live — flip its code between HTML (the standalone classes, also your htmx / Astro / Svelte /
plain-HTML usage), Vue; HTML is the default.
Classes
A checkbox is a block class on the <label> wrapper plus single-class token utilities — one class
repoints one token; no paired base class is needed. The Vue props in Framework API
map 1:1 to these.
| Class | Type | Description |
|---|---|---|
ori-checkbox | Block | Required base class — applied to the label wrapper. |
ori-color_* | Color | primary · secondary · success · warn · danger · info · surface · background |
ori-font-size_* | Size | xs · sm · md · lg · xl · xxl · text (box and label scale together off the font size) |
ori-checkbox__input | Part | the visually-hidden native input type=checkbox |
ori-checkbox__box | Part | the visible styled square; aria-hidden |
ori-checkbox__label | Part | the text label rendered next to the box |
ori-checkbox_disabled | State | added by the component when disabled; dims the wrapper |
disabled · aria-invalid | State | real attributes on the input, not classes |
Colors
Every semantic color role. The accent fill and focus ring track ori-color.
<label class="ori-checkbox ori-color_primary" for="c1">
<input id="c1" type="checkbox" class="ori-checkbox__input" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Primary</span>
</label>
<!-- swap the color class: ori-color_primary → ori-color_success / ori-color_danger / ori-color_info / … -->
Sizes
xs → xxl. The box and label scale together because ori-font-size is set on the wrapper and
the box dimensions use em units.
<!-- box and label scale together off ori-font-size_* -->
<label class="ori-checkbox ori-font-size_sm" for="sm1">
<input id="sm1" type="checkbox" class="ori-checkbox__input" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">sm</span>
</label>
<label class="ori-checkbox ori-font-size_xl" for="xl1">
<input id="xl1" type="checkbox" class="ori-checkbox__input" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">xl</span>
</label>
States
disabled is the native attribute; invalid sets aria-invalid="true" on the input.
<label class="ori-checkbox ori-checkbox_disabled" for="d1">
<input id="d1" type="checkbox" class="ori-checkbox__input" disabled />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Disabled</span>
</label>
<label class="ori-checkbox" for="inv1">
<input id="inv1" type="checkbox" class="ori-checkbox__input" aria-invalid="true" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Invalid</span>
</label>
Color × size
Color and size compose freely.
<label class="ori-checkbox ori-color_danger ori-font-size_lg" for="dl1">
<input id="dl1" type="checkbox" class="ori-checkbox__input" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Danger lg</span>
</label>
Checkbox group (array v-model)
Pass value on each checkbox and bind a shared array model. The native checkbox group mechanism
handles checked state — no extra logic needed.
<!-- array binding is Vue-specific; in plain HTML use a name attribute for the group -->
<label class="ori-checkbox ori-color_primary" for="a">
<input id="a" type="checkbox" class="ori-checkbox__input" name="opts" value="a" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Option A</span>
</label>
<label class="ori-checkbox ori-color_primary" for="b">
<input id="b" type="checkbox" class="ori-checkbox__input" name="opts" value="b" />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">Option B</span>
</label>
Common patterns
A real-world terms-and-conditions gate — required + invalid give the user feedback before
submit.
<form>
<label class="ori-checkbox ori-color_primary" for="terms">
<input id="terms" type="checkbox" class="ori-checkbox__input" required />
<span class="ori-checkbox__box" aria-hidden="true"></span>
<span class="ori-checkbox__label">I agree to the terms and conditions</span>
</label>
<button type="submit">Continue</button>
</form>
Accessibility
The accessibility contract holds across every layer — the standalone classes and the Vue component render the same attributes and keyboard behaviour.
- A real
<input type="checkbox">drives all keyboard and form behavior; the visual__boxisaria-hidden="true". - The wrapping
<label>has itsforattribute linked to the inputid(auto-generated viauseId(), overridable with theidprop) — clicking anywhere on the label or its text toggles the checkbox. - Focus is visible via
:focus-visibleon the__box(2 px outline usingvar(--ori-color)); the ring never appears on mouse click. disabledis the real native attribute — the input is excluded from tab order and form submission automatically; the wrapper dims viaori-checkbox_disabled.invalidsetsaria-invalid="true"on the input; pair it with anaria-describedbypointing at visible error text for a complete a11y contract.
| Key | Action |
|---|---|
Tab | Moves focus to / away from the checkbox. |
Space | Toggles the checked state. |
Framework API
The props, events, and slots of the Vue component. The standalone CSS layer has no component API — its surface is the classes above. (Svelte bindings are planned.)
Props
| Prop | Type | Default | Description |
|---|---|---|---|
color | ThemeColor | 'primary' | Accent color for the checked fill and focus ring. |
disabled | boolean | false | Native disabled on the input; adds ori-checkbox_disabled (opacity) to the wrapper. |
id | string | — | Overrides the auto-generated useId() for the input/label pair. |
invalid | boolean | — | Sets aria-invalid="true" on the input to signal a validation error. |
label | string | — | Visible text rendered inside ori-checkbox__label. Omit when providing your own slot content. |
required | boolean | — | Sets the native required attribute on the input. |
size | ActionSize | 'md' | Font (and therefore box) scale: xs · sm · md · lg · xl · xxl · text. |
value | string | number | — | Bound to the array model for a native checkbox group; omit for a single boolean v-model. |
Events & attributes
OriCheckbox sets inheritAttrs: false and forwards $attrs directly to the <input> element
with v-bind="$attrs". This means native listeners and HTML attributes bind to the real input, not
the outer <label>:
@change,@focus,@blur— fire on the<input>name,form,autocomplete,aria-describedby— forwarded to the<input>
The two-way binding is handled by defineModel — use v-model for boolean (single) or array
(group) state; the component emits update:modelValue internally.
Slots
| Slot | Description |
|---|---|
default | Rich label content, rendered in place of the label prop (which is the fallback). It stays inside the native <label>, so the for/id association holds — use it for an inline link or other markup. |