Chip
A compact, interactive element used for filtering, tagging, or toggling selections. Supports two sizes and color variants, selected and disabled states, optional leading and trailing icons, and polymorphic rendering.
import { Chip } from "@tenstorrent/vesper/chip";
import { CaretDown } from "@tenstorrent/vesper/icons";
export default function ChipDemo() {
return (
<div
style={{
display: "flex",
gap: "var(--vesper-spacing-2)",
}}
>
<Chip>All</Chip>
<Chip selected>Models</Chip>
<Chip>Datasets</Chip>
<Chip iconRight={<CaretDown />}>More</Chip>
</div>
);
}Options
| Prop | Type | Description | Default |
|---|---|---|---|
variant | "default" | "contrast" | The visual style variant of the chip. | "default" |
size | "sm" | "md" | The size of the chip. Affects height and typography. | "md" |
selected | boolean | Whether the chip is currently selected. Reflected via aria-pressed when rendered as a button. | false |
disabled | boolean | When true, renders the chip in a disabled state and prevents interaction. | false |
iconLeft | ReactNode | An optional icon element rendered to the left of the chip content. | — |
iconRight | ReactNode | An optional icon element rendered to the right of the chip content. | — |
onChange | (selected: boolean) => void | Callback fired when the chip is clicked. Receives the next selected state. | — |
as | ElementType | The root element type for polymorphic rendering. | "button" |
children | ReactNode | The content of the chip. | — |
You may also pass additional props to the underlying element. For example, you may wish to give the <Chip> instance a custom aria-label, type, title, etc.
Examples
Basic usage
By default, a Chip renders as a button using the default variant at md size:
import { Chip } from "@tenstorrent/vesper/chip";
export default function BasicChip() {
return <Chip>Label</Chip>;
}Sizes
A Chip can be rendered in one of two sizes: sm and md:
import { Chip } from "@tenstorrent/vesper/chip";
export default function ChipSizes() {
return (
<div
style={{
display: "flex",
gap: "var(--vesper-spacing-2)",
}}
>
<Chip size="sm">Small</Chip>
<Chip size="md">Medium</Chip>
</div>
);
}Variants
A Chip can be rendered in one of two variants. The default variant sits on your app's regular surfaces, while the contrast variant inverts the chip's colors so it stands out against a subdued or tinted background:
import { Chip } from "@tenstorrent/vesper/chip";
export default function ChipVariants() {
return (
<div
style={{
display: "flex",
gap: "var(--vesper-spacing-2)",
}}
>
<Chip>Default</Chip>
<Chip variant="contrast">Contrast</Chip>
</div>
);
}Selected state
Passing selected renders a chip in its selected state, which inverts the chip's colors. Both variants support this state:
import { Chip } from "@tenstorrent/vesper/chip";
export default function SelectedChips() {
return (
<div
style={{
display: "flex",
gap: "var(--vesper-spacing-2)",
}}
>
<Chip selected>Default</Chip>
<Chip variant="contrast" selected>
Contrast
</Chip>
</div>
);
}Disabled
Passing disabled prevents interaction and renders the chip with a muted appearance:
import { Chip } from "@tenstorrent/vesper/chip";
export default function DisabledChip() {
return <Chip disabled>Disabled</Chip>;
}When a Chip renders as a button, disabled maps to the native disabled attribute. When it renders as any other element, it is marked with aria-disabled, removed from the tab order, and its pointer, keyboard, and focus events are suppressed.
With icons
The iconLeft and iconRight props render an icon before or after the chip's content. A leading icon is useful for hinting at what the chip filters, while a trailing icon typically signals that more options are available:
import { Chip } from "@tenstorrent/vesper/chip";
import { CaretDown, Close, Globe, Search } from "@tenstorrent/vesper/icons";
export default function ChipsWithIcons() {
return (
<div
style={{
display: "flex",
gap: "var(--vesper-spacing-2)",
}}
>
<Chip iconLeft={<Search />}>Search</Chip>
<Chip iconRight={<CaretDown />}>Sort by</Chip>
<Chip iconLeft={<Globe />} iconRight={<Close />} selected>
Region
</Chip>
</div>
);
}onChange handler like any other part of the chip. If you need a dedicated action (dismissing a filter, for example), render a separate control next to the chip instead.Handling selection
A Chip does not manage its own selected state. Clicking one fires onChange with the next selected state, which you store and pass back in via the selected prop:
import { useState } from "react";
import { Chip } from "@tenstorrent/vesper/chip";
export default function ControlledChip() {
const [selected, setSelected] = useState(false);
return (
<Chip selected={selected} onChange={setSelected}>
Toggle me
</Chip>
);
}Since chips are clickable, they also accept an onClick handler. Both onChange and onClick fire when a chip is clicked.
Polymorphic usage
You can use the as prop to specify what underlying element to render. In this case, we are passing as="a" to render the Chip as an anchor link, which is helpful when a chip navigates to a filtered view rather than toggling state in place:
import { Chip } from "@tenstorrent/vesper/chip";
import { Globe } from "@tenstorrent/vesper/icons";
export default function ChipAsLink() {
return (
<Chip as="a" href="#polymorphic-usage" iconLeft={<Globe />}>
Browse all regions
</Chip>
);
}aria-pressed is only applied when a Chip renders as a button. When rendering as another element, add the semantics that match its behaviour — for example aria-current="page" on a link that points at the currently active filter.