PixelCheckbox

Controlled boolean checkbox with a chunky pixel check mark, tone-aware fill, and optional form serialization.

  • Controlled — checked + onChange (React), v-model:checked (Vue), [(checked)] or forms (Angular) — or uncontrolled with defaultChecked
  • Seven tones via the shared toneMap palette
  • Pixel and linear surface variants share the same API
  • Hidden mirror input lets it participate in native <form> submissions when name is set
  • Renders as role="checkbox" with aria-checked, aria-disabled, and aria-required
Status
stable
Category
forms
Since
v1.0.0

API

import { PixelCheckbox } from '@pxlkit/ui-kit';
PropTypeDefaultDescription
label (required)string—Label rendered next to the box.
checkedboolean—Controlled checked state.
defaultCheckedboolean—Uncontrolled initial checked state.
onChange(next: boolean) => void—Fires with the next checked value when clicked.
disabledbooleanfalseDisables interaction + grays out the control.
tone'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral''green'Visual tone for the checked state. Default: 'green'.
surface'pixel' | 'linear'—Surface variant. Inherits from PxlKitSurfaceProvider when omitted.
namestring—Form-serialization name. Hidden mirror input sends 'on' / ''.
valuestring'on'HTML form value when checked. Defaults to 'on'.
requiredboolean—Marks the field as required for native form validation.
idstring—DOM id forwarded to the trigger.

ref points to <button>.

Accessibility

WCAG target: 2.1 AA

  • checkbox

Rendered as a <button type="button"> with role="checkbox" and aria-checked reflecting the boolean state. aria-disabled and aria-required mirror the disabled and required props. When a name prop is supplied a hidden <input> is emitted alongside so the value participates in native <form> submissions only while checked. Keyboard focus shows on the box: a ring in the tone on the linear surface, the box's edge on the pixel surface, whose cut corners would clip a ring.

Keyboard

KeyActionWhen
SpaceToggles the checkbox between checked and unchecked.—
EnterSubmits the enclosing form (native <button type="button"> behavior is keyboard-activated via Space; Enter falls back to form submission).—
TabMoves focus to the next focusable element in the tab order.—

Usage

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Default() {
  const [checked, setChecked] = useState(false);
  return (
    <PixelCheckbox
      label="Accept terms"
      checked={checked}
      onChange={setChecked}
    />
  );
}

Examples

Default

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Default() {
  const [checked, setChecked] = useState(false);
  return (
    <PixelCheckbox
      label="Accept terms"
      checked={checked}
      onChange={setChecked}
    />
  );
}

Checked

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Checked() {
  const [checked, setChecked] = useState(true);
  return (
    <PixelCheckbox
      label="Subscribe to newsletter"
      checked={checked}
      onChange={setChecked}
    />
  );
}

Tones

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Tones() {
  const [values, setValues] = useState<Record<string, boolean>>({
    neutral: true,
    green: true,
    cyan: true,
    gold: true,
    red: true,
    purple: true,
    pink: true,
  });
  return (
    <div className="space-y-2">
      <PixelCheckbox
        label="Neutral"
        tone="neutral"
        checked={values.neutral}
        onChange={(v) => setValues((s) => ({ ...s, neutral: v }))}
      />
      <PixelCheckbox
        label="Green"
        tone="green"
        checked={values.green}
        onChange={(v) => setValues((s) => ({ ...s, green: v }))}
      />
      <PixelCheckbox
        label="Cyan"
        tone="cyan"
        checked={values.cyan}
        onChange={(v) => setValues((s) => ({ ...s, cyan: v }))}
      />
      <PixelCheckbox
        label="Gold"
        tone="gold"
        checked={values.gold}
        onChange={(v) => setValues((s) => ({ ...s, gold: v }))}
      />
      <PixelCheckbox
        label="Red"
        tone="red"
        checked={values.red}
        onChange={(v) => setValues((s) => ({ ...s, red: v }))}
      />
      <PixelCheckbox
        label="Purple"
        tone="purple"
        checked={values.purple}
        onChange={(v) => setValues((s) => ({ ...s, purple: v }))}
      />
      <PixelCheckbox
        label="Pink"
        tone="pink"
        checked={values.pink}
        onChange={(v) => setValues((s) => ({ ...s, pink: v }))}
      />
    </div>
  );
}

Surfaces

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Surfaces() {
  const [pixel, setPixel] = useState(true);
  const [linear, setLinear] = useState(true);
  return (
    <div className="space-y-2">
      <PixelCheckbox
        label="Pixel surface"
        surface="pixel"
        checked={pixel}
        onChange={setPixel}
      />
      <PixelCheckbox
        label="Linear surface"
        surface="linear"
        checked={linear}
        onChange={setLinear}
      />
    </div>
  );
}

Disabled

import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Disabled() {
  return (
    <div className="space-y-2">
      <PixelCheckbox
        label="Disabled unchecked"
        disabled
        checked={false}
        onChange={() => {}}
      />
      <PixelCheckbox
        label="Disabled checked"
        disabled
        checked={true}
        onChange={() => {}}
      />
    </div>
  );
}

Required

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Required() {
  const [checked, setChecked] = useState(false);
  return (
    <PixelCheckbox
      label="I agree to the terms"
      required
      checked={checked}
      onChange={setChecked}
    />
  );
}

With form name

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function WithFormName() {
  const [checked, setChecked] = useState(true);
  return (
    <form>
      <PixelCheckbox
        label="Remember me"
        name="remember"
        value="yes"
        checked={checked}
        onChange={setChecked}
      />
    </form>
  );
}

Group

import { useState } from 'react';
import { PixelCheckbox } from '@pxlkit/ui-kit';

export function Group() {
  const [prefs, setPrefs] = useState({
    email: true,
    sms: false,
    push: true,
  });
  return (
    <div className="space-y-2">
      <PixelCheckbox
        label="Email notifications"
        checked={prefs.email}
        onChange={(v) => setPrefs((s) => ({ ...s, email: v }))}
      />
      <PixelCheckbox
        label="SMS notifications"
        checked={prefs.sms}
        onChange={(v) => setPrefs((s) => ({ ...s, sms: v }))}
      />
      <PixelCheckbox
        label="Push notifications"
        checked={prefs.push}
        onChange={(v) => setPrefs((s) => ({ ...s, push: v }))}
      />
    </div>
  );
}

Related