← All components

Primitive · 5 of 13

Checkbox

Two variants × two sizes. The native input is stripped with appearance: none and the tick is a scaled pseudo-element carrying the real checked-icon.svg.

Vue island src/components/common/Checkbox.vue rendered live from compiled/Checkbox.js 4 combinations

Props

PropTypeNotes
id *stringAlso passed as autocomplete, which is unusual — see findings.
label *stringRendered beside the box inside the same <label>.
variant'primary' | 'secondary'primary is bare; secondary adds a filled pill around the pair.
size'small' | 'medium'medium (24px) is the default; small is 16px.

There is no modelValue and no emit. This component holds no state and reports nothing to its parent — while Radio, InputText and TextField all take modelValue and emit update:modelValue. See the findings.

The matrix

These four are the real Checkbox.vue — compiled from source_examples/ and mounted as Vue islands, not HTML imitations. Click them. Hover them too — the tick previews at full scale on hover, not only when checked.

Primary · medium variant="primary" size="medium" 2px border in --color-outline-primary-hover #1B0D4E → hover #5F20FE.
Primary · small size="small" 16px box, 12px label. Shown checked — set on the DOM node from outside, because the API cannot express it (see findings).
Secondary · medium variant="secondary" Pill on #0F0F15 (the site’s gray-1100). Uses outline, not border, and fills solid violet when checked.
Secondary · small variant="secondary" size="small" The filter-chip form. Checked state drops the outline entirely.

Findings

The tick transition leans on a variable the component never defines. Source declares transition: var(--default-transition-duration) transform ease-in-out; and --default-transition-duration appears nowhere in the project's own code. It resolves anyway — to 150ms from Tailwind's default theme, which the build emits because transition-colors is in use. So inside the site (and here, via tw-bridge.css) the tick animates; lift the component out of a Tailwind build and the shorthand collapses, snapping the tick from scale(0) to scale(1). A self-contained fix would name a real duration — the system ships --transition-base (200ms ease). Radio.vue line 61 carries the same declaration and the same dependency.

The component is stateless and unreported. No modelValue, no defineEmits, no :checked binding. The parent cannot set the checked state and is never told when it changes; the only way to read one is to query the DOM by id. Every other form component here uses v-model, so this is inconsistent as well as limiting.

Hover shows a tick that is not there. input:hover::before scales the tick to 1 exactly as :checked does, so hovering an unchecked box renders it as checked. The mark disappears again on mouse-out. With no border or fill change to distinguish the two, a user cannot tell a hovered-empty box from a checked one while the pointer is on it.

autocomplete is bound to id. :autocomplete="id" puts an arbitrary identifier where the spec expects a known token. Browsers ignore unrecognized values, so this is inert rather than harmful — but it means autofill is not actually being configured.