# 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 (
{ event.preventDefault(); const data = new FormData(event.currentTarget); setSubmitted(data.getAll("addons").join(", ") || "none"); }} > {submitted !== null && ( Submitted values: addons={submitted} )} ); } ``` 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 ( ); } ```