VariantGrid
StableA set of made options where you pick one, with empty slots held for ones still coming.
Also known as variations grid, results grid, image grid
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Four options, one picked
const [sel, setSel] = useState("a");
<VariantGrid
selectedId={sel}
onSelect={setSel}
variants={[
{ id: "a", label: "Variant A", node: <div className="size-full bg-fg" /> },
{ id: "b", label: "Variant B", node: <div className="size-full bg-lime" /> },
{ id: "c", label: "Variant C", node: <div className="size-full bg-sunken" /> },
{ id: "d", label: "Variant D", node: <div className="size-full bg-line-strong" /> },
]}
/>Each option has a name for screen readers. Tab to the picked tile, then use the arrow keys, Home and End.
When to use it
Shows options the assistant made as square tiles and lets people pick one. Empty slots hold space for options still on the way, so tiles do not jump around.
Made of: Option tile · AI label · Check mark · Loading placeholder
Use it for
- Picking one of several generated images or designs.
- A round of options that arrive one by one: set loadingCount.
- Comparing options side by side before opening one in a canvas.
Not for
- Picking several options at once.
- Media that people look at but do not choose between: use MediaGrid.
- Buttons to vary, upscale or remix one option: use VariationActions.
Do and avoid
Do
- Give each option its own name.
- Hold space for options that are still arriving.
- Make the content fill the square tile.
- Mark made images with the AI label. VariantTile adds it for you.
- Update selectedId in onSelect, since arrow keys pick as they move.
Avoid
- Do not use it to pick several. It allows one choice.
- Do not put buttons inside a tile. The whole tile is the button.
- Do not rely on border color alone to show the pick. The check mark covers it.
On a phone
- Tiles show in two columns on a phone and in four columns from 600px wide, and each tile stays square.
- Tiles are tapped to select, and the selected tile shows a check mark, so selection does not depend on hover.
- Loading slots are the same square size, so the grid does not jump when the options arrive.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| variantsrequired | Variant[] | none | Options to show. Variant is { id: string; node: ReactNode; label: string }. The node fills a square tile. |
| selectedId | string | none | Id of the chosen variant. Leave undefined for no selection. |
| onSelectrequired | (id: string) => void | none | Called with the id when a tile is clicked. |
| loadingCount | number | 0 | Number of skeleton squares appended after the variants. |
"Show code under the preview gives the code for the example on the stage."
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- selected
- The tile whose id matches selectedId is checked and is the one tab stop.
- loading
- Pass loadingCount to append that many shimmering placeholder tiles.
- keyboard
- Arrow keys, Home and End move focus between tiles and select the one reached.
- empty
- With no variants, only loading placeholders (if any) are drawn.
Tokens
Change one of these and every part that uses it follows.
--fg (selected border)--border / --border-strong--shadow-md--surface-sunken (skeleton)rounded-2xl tiles
Built in
- It is a group of choices named "Generated variants". Each tile has its own name, and screen readers say which one is picked.
- Only one tile is a Tab stop. Arrow keys move and pick, wrapping at the ends, and Home and End jump to the first and last.
- The pick shows a check mark and a thicker border, not color alone.
- Loading slots are hidden from screen readers.
- Screen readers hear when options start generating and when new ones arrive, such as "4 options ready".
What you need to do
- Give each variant a label that tells it apart, not just a letter.
- Set label, loadingMessage and readyMessage when you translate.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide