# Latch checkbox

A checkbox as a latching push-key. Press it and it sinks and stays down with its mark lit amber; press again and it springs back up. Mixed holds it half-down with a dash. Small enough for lists and table rows.

- Category: Essentials
- Docs: https://bevel-ui.vercel.app/components/latch-checkbox
- Import from: `@/components/ui/latch-checkbox`

## Install

```bash
npx shadcn@latest add @bevel/latch-checkbox
```

npm dependencies (installed by the CLI): `@base-ui/react`, `cn`.

## Anatomy

```tsx
<LatchCheckboxGroup value={allowed} onValueChange={setAllowed} allValues={all}>
  <LatchCheckboxField>
    <LatchCheckbox parent />
    <LatchCheckboxLabel />
  </LatchCheckboxField>
  <LatchCheckboxField>
    <LatchCheckbox value="read" />
    <LatchCheckboxLabel />
    <LatchCheckboxDescription />
  </LatchCheckboxField>
</LatchCheckboxGroup>
```

## Parts

| Part | Renders | Description |
| --- | --- | --- |
| `LatchCheckbox` | Checkbox | checked, defaultChecked, onCheckedChange, indeterminate, disabled, name. In a group: value, or parent to toggle them all. Space presses it. Alone, give it an aria-label. |
| `LatchCheckboxField` | Field.Root | The key with its label beside it and an optional description below. |
| `LatchCheckboxLabel` | Field.Label | Names the checkbox. Clicking it presses the key. |
| `LatchCheckboxDescription` | Field.Description | Describes the checkbox. |
| `LatchCheckboxGroup` | CheckboxGroup | value (the values that are down), defaultValue, onValueChange, allValues for a parent key. Name it with aria-labelledby. |

## Example: Agent permissions

Which tools an agent may use. The top key presses them all, and sits half-down while only some are on.

```tsx
"use client"

import * as React from "react"
import {
  LatchCheckbox,
  LatchCheckboxDescription,
  LatchCheckboxField,
  LatchCheckboxGroup,
  LatchCheckboxLabel,
} from "@/components/ui/latch-checkbox"

const tools = [
  { value: "read", label: "Read files", description: "Anything in the repository." },
  { value: "write", label: "Edit files", description: "Changes land on a branch, never main." },
  { value: "shell", label: "Run commands", description: "Tests, builds and linters, in a sandbox." },
  { value: "web", label: "Browse the web", description: "Docs and package registries." },
]

/** What an agent may do. The top key presses or releases them all, and sits half-down when some are on. */
export function LatchCheckboxPermissions() {
  const [allowed, setAllowed] = React.useState(["read", "shell"])
  return (
    <div className="flex w-full flex-col gap-4 rounded-xl border bg-card p-5">
      <div>
        <p id="agent-tools" className="text-sm font-semibold">
          Tools for the review agent
        </p>
        <p className="text-xs text-muted-foreground">
          {allowed.length} of {tools.length} allowed
        </p>
      </div>
      <LatchCheckboxGroup
        aria-labelledby="agent-tools"
        value={allowed}
        onValueChange={setAllowed}
        allValues={tools.map((t) => t.value)}
        className="gap-3"
      >
        <LatchCheckboxField className="border-b pb-3">
          <LatchCheckbox parent />
          <LatchCheckboxLabel>All tools</LatchCheckboxLabel>
        </LatchCheckboxField>
        {tools.map((tool) => (
          <LatchCheckboxField key={tool.value}>
            <LatchCheckbox value={tool.value} />
            <LatchCheckboxLabel>{tool.label}</LatchCheckboxLabel>
            <LatchCheckboxDescription>{tool.description}</LatchCheckboxDescription>
          </LatchCheckboxField>
        ))}
      </LatchCheckboxGroup>
    </div>
  )
}
```
