Skip to content
txbrendan/ui

Feature Grid

beta

A 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. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the website component. It also adds every component it uses. Its own files go in your components folder, 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">

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>