Skip to main content
Urbicon UI

Checkbox

A box for a single on/off choice, with an indeterminate state for partial selections.

Playground

Required for signup
Variant Style variant
Size Style variant
Tier
Mint
<Checkbox
  error=""
  helper="Required for signup"
  label="Accept terms"
/>

01 Examples

Task list

bind:checked writes every click straight back into your data, and onCheckedChange runs alongside it with the new boolean. Both hear the user only, so assigning checked in your own code stays silent.

2 of 4 done

<div
  class="border-border-subtle bg-surface-elevated flex w-full max-w-sm flex-col gap-1 rounded-2xl border p-4"
>
  {#each tasks as task (task.id)}
    <Checkbox bind:checked={task.done} label={task.label} />
  {/each}
  <p class="text-text-tertiary mt-2 text-xs">{doneCount} of {tasks.length} done</p>
</div>

Select all

A click on the mixed box turns everything on, the next one turns it all off. The click clears indeterminate on its own, so keep deriving that flag from your data rather than toggling it.
{@const allGranted = granted.length === scopes.length}
{@const someGranted = granted.length > 0 && !allGranted}
<div
  class="border-border-subtle bg-surface-elevated flex w-full max-w-sm flex-col gap-2 rounded-2xl border p-4"
>
  <Checkbox
    label="All scopes"
    checked={allGranted}
    indeterminate={someGranted}
    onCheckedChange={(on) => (granted = on ? [...scopes] : [])}
  />
  <div class="border-border-subtle ml-6 flex flex-col gap-2 border-l pl-4">
    {#each scopes as scope (scope)}
      <Checkbox
        label={scope}
        checked={granted.includes(scope)}
        onCheckedChange={(on) =>
          (granted = on ? [...granted, scope] : granted.filter((s) => s !== scope))}
      />
    {/each}
  </div>
</div>

Consent in a form

name submits the box as value (on unless you set your own), and only while it is checked. An unchecked box is absent from the FormData altogether, so data.get('terms') comes back null rather than off. error takes the helper text's place, reddens the message and sets aria-invalid.
You can withdraw your consent at any time.
<form class="flex w-full max-w-sm flex-col gap-3" onsubmit={handleConsent}>
  <Checkbox
    name="terms"
    label="I accept the terms of service"
    helper="You can withdraw your consent at any time."
    error={consentError}
  />
  <Button type="submit" size="sm" class="self-start">Continue</Button>
  {#if consented}
    <p class="text-success text-xs">Consent recorded.</p>
  {/if}
</form>

02 Micro-Interactions (Mint)

Two presets at once

The effect plays on the box, and a click-triggered preset like bounce also fires when the click lands on the label text. A single preset is a string, an array runs them together.
<Checkbox mint="glow" label="Glow on hover" checked intent="success" />
<Checkbox mint={['scale', 'glow']} label="Scale and glow together" checked intent="danger" />

03 Customization

Neon gradient

The box carries a data-state of unchecked, checked or indeterminate, and that is what this gradient keys off. Radius tier, focus ring and check-draw animation keep coming from the defaults underneath.
{@const neon = {
  box: 'border-white/25 bg-transparent text-white group-hover:border-white/40 data-[state=checked]:border-transparent data-[state=checked]:bg-linear-to-br data-[state=checked]:from-violet-500 data-[state=checked]:to-fuchsia-500 data-[state=checked]:shadow-[0_0_14px_rgba(217,70,239,0.65)]',
  label: 'text-white/90'
}}
<Checkbox checked label="Notify me about new releases" slotClasses={neon} />
<Checkbox label="Join the beta program" slotClasses={neon} />

This is one of five ways to restyle a block. See Customization for class, slotClasses, unstyled, preset and provider-level overrides.

04 Accessibility

Native semantics

The control is a real <input type="checkbox">, so it brings the form and assistive-technology behaviour with it: name and value reach FormData while the box is checked, and required is the native constraint, browser message included. indeterminate additionally sets aria-checked="mixed".

Labels and descriptions

The whole row is a <label>, so a click on the text toggles the box. The label prop fills that text, and where a design leaves it out, an aria-label passed to the component reaches the input and names it. Helper or error text links to the input through aria-describedby: an error takes the helper's place, sets aria-invalid and is the one announced through role="alert".

Keyboard

Tab to focus, Space to toggle. The focus ring shows for keyboard users only.

05 API Reference

22 props
22 props
Prop
Type
Default
Description

06 Types

Local type definitions used by this component.

8 types
Name
Kind
Category
Used by
Description

07 Installation

Import

import { Checkbox } from '@urbicon-ui/blocks';