component

Checkbox

A checkbox component for binary choices and multiple selections. Supports indeterminate state and provides proper accessibility with label association. Supports three appearances: checkbox (default square indicator), button (Panel-powered with full emphasis and feedback), and switch (horizontal toggle with sliding knob).

Default

---
import Checkbox from "../Checkbox.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "md", direction: "column" })}>
  <Checkbox id="checkbox-unchecked">Unchecked</Checkbox>
  <Checkbox id="checkbox-checked" checked>Checked</Checkbox>
  <Checkbox id="checkbox-indeterminate" indeterminate>Indeterminate</Checkbox>
  <Checkbox id="checkbox-disabled" disabled>Disabled</Checkbox>
</div>

Size

Three sizes are available across all appearances.

checkbox appearance

button appearance

---
import Checkbox from "../Checkbox.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div>
    <h3>checkbox appearance</h3>
    <div class={stack({ gap: "sm", direction: "row", align: "center" })}>
      <Checkbox id="astro-csize-sm" size="sm">Small</Checkbox>
      <Checkbox id="astro-csize-md" size="md" checked>Medium</Checkbox>
      <Checkbox id="astro-csize-lg" size="lg">Large</Checkbox>
    </div>
  </div>

  <div>
    <h3>button appearance</h3>
    <div class={stack({ gap: "sm", direction: "row", align: "center" })}>
      <Checkbox id="astro-csbtn-sm" appearance="button" size="sm"
        >Small</Checkbox
      >
      <Checkbox id="astro-csbtn-md" appearance="button" size="md" checked
        >Medium</Checkbox
      >
      <Checkbox id="astro-csbtn-lg" appearance="button" size="lg"
        >Large</Checkbox
      >
    </div>
  </div>
</div>

Button

appearance="button" composes with Panel — use feedback (primary, success, danger, warning, neutral) to control the surface.

Primary (default)

Danger

Warning

Success

---
import Checkbox from "../Checkbox.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div>
    <h3>Primary (default)</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-cbtn-p1" appearance="button" checked
        >Option 1</Checkbox
      >
      <Checkbox id="astro-cbtn-p2" appearance="button">Option 2</Checkbox>
      <Checkbox id="astro-cbtn-p3" appearance="button">Option 3</Checkbox>
    </div>
  </div>

  <div>
    <h3>Danger</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-cbtn-d1" appearance="button" feedback="danger" checked
        >Option 1</Checkbox
      >
      <Checkbox id="astro-cbtn-d2" appearance="button" feedback="danger"
        >Option 2</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Warning</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox
        id="astro-cbtn-w1"
        appearance="button"
        feedback="warning"
        checked>Option 1</Checkbox
      >
      <Checkbox id="astro-cbtn-w2" appearance="button" feedback="warning"
        >Option 2</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Success</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox
        id="astro-cbtn-s1"
        appearance="button"
        feedback="success"
        checked>Option 1</Checkbox
      >
      <Checkbox id="astro-cbtn-s2" appearance="button" feedback="success"
        >Option 2</Checkbox
      >
    </div>
  </div>
</div>

Switch

appearance="switch" renders a horizontal toggle with a sliding knob — ideal for instant on/off settings. It still uses <input type="checkbox"> under the hood, so standard form semantics and checked/disabled behavior are unchanged.

Primary (default)

Success

Warning

Danger

Sizes

Disabled

---
import Checkbox from "../Checkbox.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div>
    <h3>Primary (default)</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-p1" appearance="switch" checked>Wi-Fi</Checkbox>
      <Checkbox id="astro-csw-p2" appearance="switch">Bluetooth</Checkbox>
    </div>
  </div>

  <div>
    <h3>Success</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-s1" appearance="switch" feedback="success" checked
        >Notifications</Checkbox
      >
      <Checkbox id="astro-csw-s2" appearance="switch" feedback="success"
        >Sync</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Warning</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-w1" appearance="switch" feedback="warning" checked
        >Beta features</Checkbox
      >
      <Checkbox id="astro-csw-w2" appearance="switch" feedback="warning"
        >Experimental</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Danger</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-d1" appearance="switch" feedback="danger" checked
        >Delete on save</Checkbox
      >
      <Checkbox id="astro-csw-d2" appearance="switch" feedback="danger"
        >Purge cache</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Sizes</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-sm" appearance="switch" size="sm" checked
        >Small</Checkbox
      >
      <Checkbox id="astro-csw-md" appearance="switch" size="md" checked
        >Medium</Checkbox
      >
      <Checkbox id="astro-csw-lg" appearance="switch" size="lg" checked
        >Large</Checkbox
      >
    </div>
  </div>

  <div>
    <h3>Disabled</h3>
    <div class={stack({ gap: "sm", direction: "row" })}>
      <Checkbox id="astro-csw-dis1" appearance="switch" disabled
        >Unchecked</Checkbox
      >
      <Checkbox id="astro-csw-dis2" appearance="switch" disabled checked
        >Checked</Checkbox
      >
    </div>
  </div>
</div>

With Badge

Badges inside checkbox components scale with the component’s size via fontSize: 1rem.

checkbox appearance

button appearance

---
import Checkbox from "../Checkbox.astro";
import PindobaBadge from "@pindoba/astro-badge";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div>
    <h3>checkbox appearance</h3>
    <div class={stack({ gap: "sm", direction: "row", align: "center" })}>
      <Checkbox id="astro-badge-cb-sm" size="sm" checked>
        Small <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
      <Checkbox id="astro-badge-cb-md" size="md" checked>
        Medium <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
      <Checkbox id="astro-badge-cb-lg" size="lg" checked>
        Large <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
    </div>
  </div>

  <div>
    <h3>button appearance</h3>
    <div class={stack({ gap: "sm", direction: "row", align: "center" })}>
      <Checkbox id="astro-badge-cbtn-sm" appearance="button" size="sm" checked>
        Small <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
      <Checkbox id="astro-badge-cbtn-md" appearance="button" size="md" checked>
        Medium <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
      <Checkbox id="astro-badge-cbtn-lg" appearance="button" size="lg" checked>
        Large <PindobaBadge feedback="primary" size="sm">3</PindobaBadge>
      </Checkbox>
    </div>
  </div>
</div>

Leading & Trailing slots

Use the leading and trailing slots to position icons, stamps, or badges at the start and end of the label. With emphasis="adaptive", badges and stamps follow the parent’s color in both unchecked and checked states. The trailing slot pins to the end of the row, which pairs well with fullWidth.

button appearance — both slots

button appearance — leading only

button appearance — trailing only

checkbox appearance

---
import Checkbox from "../Checkbox.astro";
import Badge from "@pindoba/astro-badge";
import Stamp from "@pindoba/astro-stamp";
import { Icon } from "astro-icon/components";
import { stack } from "@pindoba/styled-system/patterns";

const sizes = ["sm", "md", "lg"] as const;
---

<div class={stack({ gap: "lg", direction: "column" })}>
  <div>
    <h3>button appearance — both slots</h3>
    <div class={stack({ gap: "sm", direction: "column" })}>
      {
        sizes.map((size) => (
          <Checkbox
            id={`astro-lt-cbtn-${size}`}
            appearance="button"
            size={size}
            fullWidth
            checked={size === "md"}
          >
            <Stamp
              slot="leading"
              emphasis="adaptive"
              size="xs"
              shape="circle"
              iconFill
            >
              <Icon name="lucide:bell" />
            </Stamp>
            Notifications
            <Badge slot="trailing" emphasis="adaptive" size="sm">
              12
            </Badge>
          </Checkbox>
        ))
      }
    </div>
  </div>

  <div>
    <h3>button appearance — leading only</h3>
    <div class={stack({ gap: "sm", direction: "column" })}>
      {
        sizes.map((size) => (
          <Checkbox
            id={`astro-lt-cbtn-leading-${size}`}
            appearance="button"
            size={size}
            fullWidth
            checked={size === "md"}
          >
            <Stamp
              slot="leading"
              emphasis="adaptive"
              size="xs"
              shape="circle"
              iconFill
            >
              <Icon name="lucide:bell" />
            </Stamp>
            Notifications
          </Checkbox>
        ))
      }
    </div>
  </div>

  <div>
    <h3>button appearance — trailing only</h3>
    <div class={stack({ gap: "sm", direction: "column" })}>
      {
        sizes.map((size) => (
          <Checkbox
            id={`astro-lt-cbtn-trailing-${size}`}
            appearance="button"
            size={size}
            fullWidth
            checked={size === "md"}
          >
            Notifications
            <Badge slot="trailing" emphasis="adaptive" size="sm">
              12
            </Badge>
          </Checkbox>
        ))
      }
    </div>
  </div>

  <div>
    <h3>checkbox appearance</h3>
    <div class={stack({ gap: "sm", direction: "column" })}>
      {
        sizes.map((size) => (
          <Checkbox
            id={`astro-lt-cb-${size}`}
            size={size}
            checked={size === "md"}
          >
            Tasks
            <Badge slot="trailing" emphasis="adaptive" size="sm">
              5
            </Badge>
          </Checkbox>
        ))
      }
    </div>
  </div>
</div>

Custom Styling

The passThrough prop provides per-slot escape hatches: style accepts a Panda CSS SystemStyleObject merged with the base styles, and props forwards arbitrary HTML attributes onto the element.

Custom input style via passThrough

Custom props via passThrough

---
import Checkbox from "../Checkbox.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div>
    <h3>Custom input style via passThrough</h3>
    <Checkbox
      id="checkbox-custom-style"
      passThrough={{
        input: {
          style: { borderRadius: "full" },
        },
      }}
    >
      Rounded checkbox
    </Checkbox>
  </div>

  <div>
    <h3>Custom props via passThrough</h3>
    <Checkbox
      id="checkbox-custom-props"
      passThrough={{
        root: {
          props: { "data-testid": "my-checkbox" },
        },
        input: {
          props: { "aria-label": "Accept terms and conditions" },
        },
      }}
    >
      Accept terms
    </Checkbox>
  </div>
</div>

Props

props · 11 total
prop type default req description
appearance "checkbox""button""switch" "checkbox" Visual style of the checkbox. checkbox: Default square indicator. button: Styled as a button using Panel composition. switch: Horizontal toggle with sliding knob.
feedback "primary""neutral""success""danger""warning" "primary" Color scheme applied via colorPalette. For checkbox appearance this sets the indicator accent color. For button appearance this sets the Panel feedback color.
size "sm""md""lg" "md" Size of the component.
fullWidth boolean false Expand the checkbox to fill its container width.
id string - Unique identifier for the checkbox input, required for proper label association.
checked boolean undefined Controls the checked state of the checkbox.
indeterminate boolean undefined Controls the indeterminate (partially checked) state of the checkbox.
disabled boolean undefined Disables the checkbox.
passThrough { root?: { style?: SystemStyleObject; props?: HTMLLabelAttributes }; input?: { style?: SystemStyleObject; props?: HTMLInputAttributes } } undefined Per-slot style and attribute overrides.
children Snippet undefined Label content rendered next to the checkbox.
...rest Omit<HTMLInputAttributes, 'type'> - Standard HTML input attributes (excluding type).