Skip to content
kerfjsGitHub

Checkbox

A yes or no that takes effect when the form is saved.

SourcePackage @kerf-js/veneerTry it

Preview

tsx
import { state } from '@kerf-js/core'import { Checkbox } from '@kerf-js/veneer'export function Basic() {  const on = state(true)  return (    <Checkbox      checked={on.value}      onChange={(        e: Event & { currentTarget: HTMLInputElement },      ) => (on.value = e.currentTarget.checked)}    >      Deploy on push    </Checkbox>  )}

Installation

npm install @kerf-js/veneer

Try it

Change the controls: the preview and its code update together. The address keeps what you set, so you can link to it.

Live preview
Controls
Codeupdates as you change the controls
import { Checkbox } from '@kerf-js/veneer'<Checkbox checked>Deploy on push</Checkbox>

Usage

tsx
import { Checkbox } from '@kerf-js/veneer'<Checkbox>Deploy on push</Checkbox>

With a hint

A checkbox's hint is a quieter second line under its label.

tsx
import { state } from '@kerf-js/core'import { Checkbox } from '@kerf-js/veneer'export function Hint() {  const on = state(false)  return (    <Checkbox      checked={on.value}      hint="Failed checks stop the deploy."      onChange={(        e: Event & { currentTarget: HTMLInputElement },      ) => (on.value = e.currentTarget.checked)}    >      Require checks to pass    </Checkbox>  )}

States

A checkbox can be checked, indeterminate or disabled, and can show a hint or an error.

tsx
import { Checkbox, Grid } from '@kerf-js/veneer'import { Stack, Text } from '@kerf-js/veneer'export function States() {  return (  <Grid    cols={3}    gap="group"  >    <Cell name="Off">      <Checkbox>Deploy on push</Checkbox>    </Cell>    <Cell name="On">      <Checkbox checked>Deploy on push</Checkbox>    </Cell>    <Cell name="Part of a set">      <Checkbox indeterminate>Deploy on push</Checkbox>    </Cell>    <Cell name="Hint">      <Checkbox hint="Every push to main goes live.">        Deploy on push      </Checkbox>    </Cell>    <Cell name="Invalid">      <Checkbox error="Accept this to carry on.">        Deploy on push      </Checkbox>    </Cell>    <Cell name="Disabled">      <Checkbox        checked        disabled      >        Deploy on push      </Checkbox>    </Cell>  </Grid>  )}const Cell = ({  name,  children,}: {  name: string  children?: unknown}) => (  <Stack gap="tight">    <Text      role="caption"      subtle    >      {name}    </Text>    {children}  </Stack>)

Select all

The parent shows a dash while only some are on.

tsx
import { derived, state } from '@kerf-js/core'import { Checkbox, Stack } from '@kerf-js/veneer'export function SelectAll() {  const on = state(['Deploy failed', 'Uptime drops'])  const flip = (name: string) =>    (on.value = on.value.includes(name)      ? on.value.filter((n) => n !== name)      : [...on.value, name])  const all = derived(    () => on.value.length === EVENTS.length,  )  return (    <Stack gap="tight">      <Checkbox        checked={all.value}        indeterminate={on.value.length > 0 && !all.value}        onChange={() =>          (on.value = all.value ? [] : EVENTS)        }      >        Email me about      </Checkbox>      <Stack        gap="tight"        style={          'padding-inline-start:' +          'var(--veneer-space-group)'        }      >        {EVENTS.map((name) => (          <Checkbox            key={name}            checked={on.value.includes(name)}            onChange={() => flip(name)}          >            {name}          </Checkbox>        ))}      </Stack>    </Stack>  )}const EVENTS = [  'Deploy failed',  'Deploy finished',  'Uptime drops',  'Budget reached',]

Confirm before deleting

Press Delete without ticking it.

tsx
import { state } from '@kerf-js/core'import {  Button,  Checkbox,  Row,  Stack,  Text} from '@kerf-js/veneer'export function Confirm() {  const sure = state(false)  const tried = state(false)  const gone = state(false)  const remove = () => {    tried.value = true    if (sure.value) gone.value = true  }  return (    <Stack gap="group">      <Text>        {gone.value          ? 'reports was deleted.'          : 'Deleting reports removes its 41 deploys ' +            'and all its logs.'}      </Text>      <Checkbox        checked={sure.value}        error={          tried.value && !sure.value            ? 'Tick this first.'            : undefined        }        onChange={(          e: Event & { currentTarget: HTMLInputElement },        ) => (sure.value = e.currentTarget.checked)}      >        I understand this can't be undone      </Checkbox>      <Row justify="end">        <Button          tone="critical"          onClick={remove}        >          Delete project        </Button>      </Row>    </Stack>  )}

When to use

Use it for

  • An option inside a form with a Save button
  • Picking any number from a list

Reach for something else

Accessibility

Space
Toggles
  • It is a real checkbox, and the whole label can be pressed.
  • indeterminate sets the real property, so it is announced as mixed.

API Reference

PropTypeDefaultDescription
checkedbooleanfalseWhether it is on. You own this value.
indeterminatebooleanfalseShows a dash: some of a set are on.
hintunknown—A short line under the label.
errorunknown—Replaces the hint and marks it invalid.
childrenunknown—What it contains.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="checkbox"] [data-part="control"]

controlmarklabelhint

RelatedSwitchRadio groupChip