Skip to content
Component installs need the registry setup
VegaStack Design

Field Grid

A responsive one-to-three column grid of Fields by container width, and FieldChoices — radios or checkboxes in a wrapping row.

Status
stable
Since
0.23.57
Accessibility pattern
layout only; Field, FieldSet and RadioGroup keep semantics

Last updated

A textarea takes the whole row.

Install

Add Field Grid from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/field-grid

Usage

import {
  FieldChoices,
  FieldGrid,
  FieldGridItem,
} from "@/components/ui/field-grid";

<FieldGrid>
  {specs.map((spec) => (
    <Field key={spec.id}>
      <FieldLabel htmlFor={spec.id}>{spec.name}</FieldLabel>
      <Input id={spec.id} />
    </Field>
  ))}
</FieldGrid>;

<FieldSet>
  <FieldLegend variant="label">Type</FieldLegend>
  <FieldChoices orientation="horizontal">
    <RadioGroup value={type} onValueChange={setType}>
      …
    </RadioGroup>
  </FieldChoices>
</FieldSet>;

Anatomy

FieldGrid — data-slot="field-grid" | "field-grid-body"
FieldGridItem — data-slot="field-grid-item"
FieldChoices — data-slot="field-choices"

Examples

Three columns

The default grid: one column below 28rem of its container's width, two from 28rem and three from 48rem. It follows the container, not the viewport, so the same form stays one column in a side panel. A field holding a Textarea takes the whole row by itself.

A textarea takes the whole row.

Two columns

columns={2} stops at two. FieldGridItem span="full" gives any other content the whole row.

Choices in a row

FieldChoices orientation="horizontal" sets a short set of radios (a RadioGroup placed directly inside it) or checkbox fields side by side, wrapping onto the next line when the row is full. Use it for two to five short options.

Type
Classification

Choices in a column

The default vertical stack, for longer labels or more options.

Notify me

API Reference

PropTypeDefaultDescription
columns2 | 33The most columns the grid grows to. 3 is one column below 28rem of container width, two from 28rem and three from 48rem; 2 stops at two.

Data attributes and CSS variables on FieldGrid

AttributeValues
data-columnsmirrors a prop or state value
data-slot"field-grid" | "field-grid-body"

FieldGridItem

PropTypeDefaultDescription
span"auto" | "full"'auto'full takes the whole row at every width; auto takes one cell.

Data attributes and CSS variables on FieldGridItem

AttributeValues
data-slot"field-grid-item"
data-spanmirrors a prop or state value

FieldChoices

PropTypeDefaultDescription
orientation"horizontal" | "vertical"'vertical'horizontal sets the choices side by side in a row that wraps; vertical stacks them.

Data attributes and CSS variables on FieldChoices

AttributeValues
data-orientationmirrors a prop or state value
data-slot"field-choices"

Accessibility

  • Layout only: the grid adds no roles. Each Field keeps its label, and a set of choices keeps its FieldSet and FieldLegend, which name the group for assistive tech.
  • Reading and tab order follow the source order in every column count.
  • Radio targets keep their 24px hit areas side by side: the row gap is wide enough that the invisible hit areas of neighbouring choices touch without overlapping.
ContractStates tested
Behaviourdefault, full-span
Accessibilitysemantic-html
Visualdefault, horizontal, vertical

Do / Don't

Do
Use FieldGrid for a long list of short fields (specifications, settings) and FieldChoices horizontal for two to five short options.
Don't
Put long labels side by side, or use a grid inside a narrow dialog — a FieldGroup reads better there.

On this page