The choice that has to be seen to be made: a template, a layout, a chart type. Each option is a picture, normally a rendered screenshot passed as a URL, or markup for the choices no photograph would show. The row is the trigger, the grid is width-matched to it, and the captions under the pictures can be dropped for a set whose pictures say everything.
The import and the props worth knowing about, in one place.
import { InspectorVariants } from "@/components/beste/component/inspector-variants";
// The ordinary case: a picture of each variant, by URL
<InspectorVariants
label="Template"
defaultValue="gallery"
options={[
{ value: "editorial", label: "Editorial", image: "/thumbs/editorial.png" },
{ value: "gallery", label: "Gallery", image: "/thumbs/gallery.png" },
{ value: "portfolio", label: "Portfolio", image: "/thumbs/portfolio.png", description: "Grid of work" },
]}
/>
<InspectorVariants
label="Chart"
options={charts}
value={chart}
onValueChange={setChart}
onOpenChange={(open) => console.log("grid open:", open)}
columns={2} // choices per row, three by default
ratio="16 / 9" // shape of each picture, "4 / 3" by default
fit="contain" // "cover" (default) crops to the shape; "contain" fits the whole picture in
captioned={false} // pictures alone; each cell keeps the name as its label and tooltip
placeholder="Choose one" // shown while nothing is selected
clearable // adds a "Remove Chart" button at the foot
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>
// No screenshot to point at: an abstraction, or a miniature of the real thing.
// `image` wins when both are given.
<InspectorVariants
label="Density"
options={[
{
value: "comfortable",
label: "Comfortable",
preview: (
<span className="flex size-full flex-col justify-center gap-1.5 p-2">
<span className="h-1 rounded-full bg-foreground/25" />
<span className="h-1 w-2/3 rounded-full bg-foreground/25" />
</span>
),
},
{ value: "compact", label: "Compact", preview: <MyMiniature dense /> },
]}
/>
// A picture that fails to load is marked rather than left blank: an empty box is a
// variant with nothing in it, which is a different thing.Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Enter / Space | Open the grid from the row |
|---|---|
| Tab | Walks the pictures in the order they read |
| Escape | Close the grid, leaving the value alone |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Label rendered on the left, inside the row. |
icon | LucideIcon | — | Optional leading icon shown before the label. |
options | InspectorVariant[] | — | The choices on offer. |
value | string | — | Controlled selection, by `value`. Pair it with `onValueChange`. |
defaultValue | string | — | Initial selection in uncontrolled mode. |
onValueChange | (value: string) => void | — | |
onOpenChange | (open: boolean) => void | — | Fires when the grid opens or closes. |
columns | number | 3 | Choices per row in the grid. |
ratio | string | "4 / 3" | Shape of each picture, as an aspect ratio. |
fit | "cover" | "contain" | "cover" | How an `image` fills its box. `cover` crops it to the shape, which is right for a screenshot; `contain` fits the whole thing in, which is right for a diagram or an icon on transparency that would lose its edges to a crop. |
captioned | boolean | true | Print the name (and any description) under each picture. Turn it off for a set whose pictures say everything — thumbnails of the real thing, where the names are filenames or numbers nobody reads — and the grid becomes pictures alone. The names do not go anywhere: each cell keeps them as its accessible name and its tooltip, and the row still says which one is chosen. |
clearable | boolean | — | Offer a clear button at the foot of the grid once something is selected. |
placeholder | string | — | Shown in the row while nothing is selected. |
disabled | boolean | — | Block interaction and dim the row. |
tone | "muted" | "outline" | "ghost" | "muted" | Surface treatment: filled (default), hairline outline, or bare until hover. |
size | "sm" | "default" | "lg" | "default" | Row height preset. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |