# Checkbox

> Binary input with full tristate support (checked / unchecked / indeterminate), label association, semantic colors, and keyboard activation.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://sisyphosui.com/docs/components/checkbox
- WAI-ARIA pattern: [Checkbox](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/)

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { Checkbox } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { useState } from "react";
import { Checkbox } from "@sisyphos-ui/react";

export function Terms() {
  const [agreed, setAgreed] = useState(false);
  return (
    <Checkbox
      checked={agreed}
      onChange={setAgreed}
      label="I agree to the terms"
    />
  );
}
```

### Vue 3+

```vue
<script setup lang="ts">
import { ref } from "vue";
import { Checkbox } from "@sisyphos-ui/vue";

const agreed = ref(false);
</script>

<template>
  <Checkbox v-model:checked="agreed" label="I agree to the terms" />
</template>
```

### Angular 17+

```ts
import { Component, signal } from "@angular/core";
import { Checkbox } from "@sisyphos-ui/angular";

@Component({
  selector: "app-terms",
  standalone: true,
  imports: [Checkbox],
  template: `
    <sui-checkbox
      [(checked)]="agreed"
      label="I agree to the terms"
    />
  `,
})
export class TermsComponent {
  agreed = signal(false);
}
```

## Examples

### Default

Checkbox is always controlled. Manage state in your own component.

```tsx
import { useState } from "react";
import { Checkbox } from "@sisyphos-ui/react";

export function Example() {
  const [subscribed, setSubscribed] = useState(true);
  const [agreed, setAgreed] = useState(false);

  return (
    <div className="flex flex-col gap-3">
      <Checkbox label="Subscribe to newsletter" checked={subscribed} onChange={setSubscribed} />
      <Checkbox label="I agree to the terms" checked={agreed} onChange={setAgreed} />
      <Checkbox label="Disabled — checked" checked disabled />
      <Checkbox label="Disabled — unchecked" checked={false} disabled />
    </div>
  );
}
```

### Semantic colors

```tsx
import { Checkbox } from "@sisyphos-ui/react";

export function Example() {
  return (
    <div className="flex flex-col gap-2">
      <Checkbox checked color="primary" label="Primary" onChange={() => {}} />
      <Checkbox checked color="success" label="Success" onChange={() => {}} />
      <Checkbox checked color="error"   label="Error"   onChange={() => {}} />
      <Checkbox checked color="warning" label="Warning" onChange={() => {}} />
      <Checkbox checked color="info"    label="Info"    onChange={() => {}} />
    </div>
  );
}
```

### Sizes

Three sizes match the scale system used by Input and Button.

```tsx
import { useState } from "react";
import { Checkbox } from "@sisyphos-ui/react";

export function Example() {
  const [vals, setVals] = useState({ sm: true, md: true, lg: true });

  return (
    <>
      <Checkbox label="Small"  size="sm" checked={vals.sm} onChange={(c) => setVals(v => ({ ...v, sm: c }))} />
      <Checkbox label="Medium" size="md" checked={vals.md} onChange={(c) => setVals(v => ({ ...v, md: c }))} />
      <Checkbox label="Large"  size="lg" checked={vals.lg} onChange={(c) => setVals(v => ({ ...v, lg: c }))} />
    </>
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| **checked** (required) | `boolean` | — | Current checked state. Always controlled. |
| indeterminate | `boolean` | `false` | Renders the tristate "mixed" mark and exposes `aria-checked="mixed"`. Activating promotes to `checked=true`. |
| onChange | `(checked: boolean) => void` | — | Called with the next boolean when the user toggles the input. |
| label | `ReactNode` | — | Optional label rendered next to the box. |
| color | `"neutral" \| "primary" \| "success" \| "error" \| "warning" \| "info"` | `"primary"` | Semantic color used when checked or indeterminate. |
| size | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Box dimensions. |
| radius | `"radius-xs" \| "radius-sm" \| "radius-md" \| "radius-lg" \| "radius-xl"` | — | Border radius scale. |
| disabled | `boolean` | `false` | Disables interaction and applies the disabled visual. |
| id | `string` | — | Custom id used to link the label. |

## Keyboard interactions

- **Space** — Toggles the value. Indeterminate checkboxes promote to checked.
- **Tab** — Moves focus to the next focusable element.

## Accessibility notes

- `aria-checked` reflects the visual state — `"true"`, `"false"`, or `"mixed"` for the indeterminate value.
- The DOM `indeterminate` flag is kept in sync alongside the ARIA attribute (assistive tech reads both).
- `aria-disabled` mirrors `disabled`; the underlying `<input>` is also natively disabled to block submission.
- The label is wired through `htmlFor` / `id` so screen readers announce the label when the input is focused.

<!-- exports: { "Checkbox": "@sisyphos-ui/react" } -->