Feature Grid
betaA grid of feature cells split by thin lines, each with a title, a description, and a picture above or below.
Preview
Built for agents. Checked for people.
Each part explains itself
Every part comes with notes on when to use it and when not to, so an agent picks the right one.
Checked in light and dark
The theme's color pairs are tested for contrast, in light mode and in dark mode.
One theme for every part
Color, type, and motion come from one set of tokens. Lint blocks any color outside it.
A size budget for each part
Every component has a size budget, and the check fails when one goes over it.
The code is yours
Each part is a plain source file in your app, with no runtime. Change anything you like.
words only, two to a row
Checked
Color pairs are tested for contrast.
Yours
Plain source files you can change.
narrow container
One theme for every part
Color, type, and motion from one set of tokens.
The code is yours
Change anything you like.
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the website component. It also adds every component it uses. Its own files go in your
componentsfolder, and they are yours to edit.npx shadcn@latest add @txbrendan/feature-grid
Use it for
- The feature section of a landing page, under a Headline: three cells, then two wider ones.
- Give each cell an `illustration`. The Illustrations, like Stacked Blocks or Code Key, are made for it. Add each one by its name, like `npx shadcn@latest add @txbrendan/stacked-blocks`, since this install does not bring them.
- Set `span="half"` on two cells for a row of two. Cells are a third wide by default.
- Set `illustrationFirst` when the picture should sit above the words, like a wide cell in the second row.
- Keep each description to two lines at 1280px. The pictures carry the rest.
Avoid it for
- Soft cards with gaps between them. Use Bento Grid.
- Screenshots as pictures. Build them from parts, so they stay sharp and follow the theme.
- More than six cells. Split them under two Headlines.
Props
- title
FeatureGridItem. What the feature is. It is an h3.
ReactNode
- description
FeatureGridItem. What it does, in a sentence or two.
ReactNode
- illustration
FeatureGridItem. A picture of the feature. It fills the room the words leave.
ReactNode
- illustrationFirst
FeatureGridItem. Put the picture above the words.
boolean · default false
- span
FeatureGridItem. How much of a row the cell takes, from 48rem of the grid's width.
"third" | "half" | "full" · default "third"
- className
Extra classes on the root. On FeatureGrid it holds the container query.
string
- FeatureGrid
Part. The grid: one column when narrow, six tracks from 48rem of its own width. Put FeatureGridItems inside.
ComponentProps<"div">
| Prop | Type | Default | What it does |
|---|---|---|---|
| title | ReactNode | - | FeatureGridItem. What the feature is. It is an h3. |
| description | ReactNode | - | FeatureGridItem. What it does, in a sentence or two. |
| illustration | ReactNode | - | FeatureGridItem. A picture of the feature. It fills the room the words leave. |
| illustrationFirst | boolean | false | FeatureGridItem. Put the picture above the words. |
| span | "third" | "half" | "full" | "third" | FeatureGridItem. How much of a row the cell takes, from 48rem of the grid's width. |
| className | string | - | Extra classes on the root. On FeatureGrid it holds the container query. |
| FeatureGrid | ComponentProps<"div"> | - | Part. The grid: one column when narrow, six tracks from 48rem of its own width. Put FeatureGridItems inside. |
Accessibility
- Each title is an h3, so put the grid under an h2, like a Headline.
- The Illustrations are each one image with a label, so screen readers hear a sentence per picture.
- Keep pictures free of real buttons, so nothing inside them takes focus.
- The lines between cells are outlines, so they still show in forced colors.
Examples
Three cells, then two, after adding the five Illustrations
<FeatureGrid>
<FeatureGridItem title="Each part explains itself" description="Notes on when to use each part." illustration={<StackedBlocks />} />
<FeatureGridItem title="Checked in light and dark" description="Color pairs are tested for contrast." illustration={<ContrastOrb />} />
<FeatureGridItem title="One theme for every part" description="Color, type, and motion from one set of tokens." illustration={<ThemeLayers />} />
<FeatureGridItem span="half" illustrationFirst title="A size budget for each part" description="The check fails when one goes over." illustration={<SpeedGauge />} />
<FeatureGridItem span="half" illustrationFirst title="The code is yours" description="Change anything you like." illustration={<CodeKey />} />
</FeatureGrid>Words only
<FeatureGrid>
<FeatureGridItem span="half" title="Checked" description="Color pairs are tested for contrast." />
<FeatureGridItem span="half" title="Yours" description="Plain source files you can change." />
</FeatureGrid>