Checkbox

A checkbox turns one option on or off, and a group of them lets people pick any number of options at once. For a single choice out of several use a radio, and for a setting that applies at once a switch.

Usage

<script lang="ts">
	import { Checkbox } from 'noph-ui'
</script>

<Checkbox aria-label="Unchecked" />
<Checkbox aria-label="Checked" checked />
<Checkbox aria-label="Indeterminate" indeterminate />

Disabled

<script lang="ts">
	import { Checkbox } from 'noph-ui'
</script>

<Checkbox aria-label="Unchecked" disabled />
<Checkbox aria-label="Checked" disabled checked />
<Checkbox aria-label="Indeterminate" disabled indeterminate />

Error

<script lang="ts">
	import { Checkbox } from 'noph-ui'
</script>

<Checkbox aria-label="Unchecked" issues={[{ message: 'Required' }]} />
<Checkbox aria-label="Checked" checked issues={[{ message: 'Required' }]} />
<Checkbox aria-label="Indeterminate" indeterminate issues={[{ message: 'Required' }]} />

issues is shaped like a SvelteKit remote form's field issues, so passing a field's issues() straight through is enough to drive the error state.

Label

<script lang="ts">
	import { Checkbox } from 'noph-ui'
</script>

<label style="display: flex; align-items: center"><Checkbox />Checkbox one</label>
<label style="display: flex; align-items: center"><Checkbox />Checkbox two</label>

Theming

TokenDefault value
--np-checkbox-container-shape2px
--np-checkbox-outline-color--np-color-on-surface-variant
--np-checkbox-selected-container-color--np-color-primary
--np-checkbox-selected-icon-color--np-color-on-primary
--np-checkbox-marginmax(0px, (48px - 18px) / 2)

--np-checkbox-margin is the space that grows the 18dp box into a 48dp touch target. Only shrink it where the checkbox already sits inside a large enough target of its own, such as a list item.

The hover state layer is --np-color-primary while the box is checked or indeterminate and --np-color-on-surface while it is not. The press ripple takes the other one, as in the Material 3 states.

Example

<script lang="ts">
	import { Checkbox } from 'noph-ui'
</script>

<Checkbox
	checked
	aria-label="Themed checkbox"
	--np-checkbox-container-shape="10px"
	--np-checkbox-outline-color="var(--np-color-tertiary)"
	--np-checkbox-selected-container-color="var(--np-color-error)"
	--np-checkbox-selected-icon-color="var(--np-color-on-error)"
/>

Accessibility

The component renders a native <input type="checkbox"> with the Material 3 drawing on top, so checked, focus, the space key and form submission are the browser's work, not ours. Enter does not toggle it but submits the form, like any native checkbox.

It brings no label of its own. Wrap it in a <label>, as the Label example does, or pass aria-label. The indeterminate state reports aria-checked="mixed", and issues sets aria-invalid so the error reaches assistive technology and not only the eye.

API

AttributeTypeDefaultDescription
issues{ message: string }[]undefinedDraws the checkbox in the error color and sets aria-invalid on the input when non-empty. Shaped like a SvelteKit remote form's field issues, so it wires straight in. A disabled checkbox keeps its disabled styling instead.
...attributesOmit<HTMLInputAttributes, 'type'>

Bindables

AttributeTypeDescription
indeterminateboolean | null | undefinedInput property
checkedboolean | null | undefinedInput property
group(string | number)[] | nullInput property
elementHTMLElementA reference to the root DOM element of the component. This variable is bound using bind:this, allowing direct access to the underlying HTML element for manipulation or querying within the component's logic.