# Choicebox
A card-style selection component supporting both single-select and multi-select modes. Each option displays a label and optional description with a visual checkmark indicator.
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function ChoiceboxDemo() {
return (
);
}
```
> [!NOTE]
>
> Give the group an accessible name so assistive technology can announce what the options belong to. `Choicebox` renders a `
`, so you can either pass it an `aria-label`, or point `aria-labelledby` at the heading or label that already names the group.
## Options
| Prop | Type | Description | Default |
| --------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------- |
| `name` | `string` | The name attribute shared by all inputs in the group, used for form submission. | — |
| `options` | `ChoiceboxItem[]` | The list of options to render. Each has `value`, `label`, optional `description`, `disabled`, and `id`. | — |
| `disabled` | `boolean` | When `true`, disables all options in the group. | `false` |
| `multiselect` | `boolean` | When `true`, enables multi-select (checkbox) mode. Otherwise single-select (radio). | `false` |
| `value` | `string` | The currently selected value (single-select, controlled). | — |
| `defaultValue` | `string` | The initially selected value (single-select, uncontrolled). | — |
| `values` | `string[]` | The currently selected values (multi-select, controlled). | — |
| `defaultValues` | `string[]` | The initially selected values (multi-select, uncontrolled). | — |
| `onChange` | `(value: string) => void \| (values: string[]) => void` | Callback fired when the selection changes. | — |
| `required` | `boolean` | When `true`, a selection is required (single-select only). | `false` |
| `min` | `number` | Minimum selections required (multi-select only). | `0` |
| `max` | `number` | Maximum selections allowed (multi-select only). | `Infinity` |
All other props are forwarded to the wrapping `` element.
### `ChoiceboxItem` options
| Property | Type | Description |
| ------------- | --------- | ---------------------------------------------------------------------------------------- |
| `value` | `string` | The value submitted with form data and passed to `onChange`. Must be unique. |
| `label` | `string` | The text displayed for this option. |
| `description` | `string` | An optional secondary line of text displayed below the label. |
| `disabled` | `boolean` | When `true`, prevents this option from being selected. Defaults to `false`. |
| `id` | `string` | An `id` applied to this option's ` `, used to reference it from validation errors. |
Use a `Choicebox` when each option benefits from a description and a large, card-style target. For a plain list of mutually exclusive options, reach for [the `RadioGroup` component](./radio-group.mdx), and for a single boolean choice, reach for [the `Checkbox` component](./checkbox.mdx).
## Examples
### Defining options
Render a `Choicebox` by passing an array of `ChoiceboxItem` objects as the `options` prop. Each item describes a single card. `value` is what gets submitted and reported to `onChange`, `label` is the text displayed on the card, and the optional `description` adds a secondary line below it:
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function ChoiceboxOptions() {
return (
);
}
```
Options without a `description` render as a more compact card, as seen with the `"Asia Pacific"` option above.
### Single-select
By default, a `Choicebox` operates in single-select mode, rendering each option as a radio input so that picking one deselects the others. Pass `defaultValue` to select an option initially:
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function UncontrolledChoicebox() {
return (
);
}
```
To control the selection, pass `value` alongside `onChange`, which receives the newly selected value:
```tsx demo
import { useState } from "react";
import { Choicebox } from "@tenstorrent/vesper/choicebox";
import { Typography } from "@tenstorrent/vesper/typography";
export default function ControlledChoicebox() {
const [value, setValue] = useState("monthly");
return (
Selected value: {value}
);
}
```
### Multi-select
Passing `multiselect` renders each option as a checkbox, allowing any number of them to be selected. In this mode the uncontrolled prop is `defaultValues`, and `onChange` receives the full array of selected values:
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function MultiSelectChoicebox() {
return (
);
}
```
Controlled multi-select works the same way as single-select, except that you pass `values` instead of `value`:
```tsx demo
import { useState } from "react";
import { Choicebox } from "@tenstorrent/vesper/choicebox";
import { Typography } from "@tenstorrent/vesper/typography";
export default function ControlledMultiSelectChoicebox() {
const [values, setValues] = useState(["analytics"]);
return (
Selected values: {values.join(", ") || "none"}
);
}
```
### Disabling options
Pass `disabled` to an individual option to prevent it from being selected while leaving the rest of the group interactive. You can also pass `disabled` to the `Choicebox` component itself to disable every option at once:
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function DisabledChoiceboxOptions() {
return (
);
}
```
### Usage in forms
`Choicebox` renders native inputs inside a ``, so it works with regular form submission and native validation. Every selected option submits its `value` under the group's `name`, which means a multi-select group can submit several values at once:
```tsx demo
import { useState } from "react";
import { Button } from "@tenstorrent/vesper/button";
import { Choicebox } from "@tenstorrent/vesper/choicebox";
import { Typography } from "@tenstorrent/vesper/typography";
export default function FormChoiceboxDemo() {
const [submitted, setSubmitted] = useState(null);
return (
);
}
```
The `min` and `max` props set a custom validation message on the group, so the form above refuses to submit until between one and two add-ons are selected. In single-select mode, pass `required` instead to require that one of the options is picked:
```tsx demo
import { Choicebox } from "@tenstorrent/vesper/choicebox";
export default function RequiredChoicebox() {
return (
);
}
```