Feature Grid
Two to six parallel benefits or ways to take part, each a sentence or two, led by an icon, a numeral or a small drawing.
import {
FeatureGrid,
FeatureGridBody,
FeatureGridCell,
FeatureGridHeading,
FeatureGridIcon,
FeatureGridList,
} from '@fairgarden-private/design/components/FeatureGrid'
Use one leader type per grid, never mixed. Icons are Material Symbols Rounded at the block tier and fill in the accent; never put a colored tile behind them. A FeatureGridLink inside the heading links the whole cell, and the cell draws the focus ring. Don't use a feature grid for measurable attributes (use a spec sheet), and split it into two modules rather than exceed six cells.
Kinds
Kinds
icon is the default. numbered draws zero-padded numerals in outline circles from the list order and separates cells with inset rules, which turn vertical once the cells sit in a row. rule-topped opens each cell with a hairline. framed sets the cells 2 × 2 inside one faced frame, which opens a light face on every ground. The grid stacks below 768 px of its container, runs 3-up from 768 and up to 4-up from 1024. header renders the §11.8 section header above the cells: pass SectionHeader props (the grid is then labelled by its heading) or any node; FeatureGridHeader still takes children.
Visit
Plan your walk
Find a trail
Search 40 preserves by distance, terrain and dogs allowed.Take the map
Download printable maps that work without a signal.Ask a steward
Our stewards answer questions within two days.
Pick a date
Crew days run every second Saturday.Bring gloves
We supply tools, water and snacks.Meet at the kiosk
We start at nine and finish by noon.
Pick a date
Crew days run every second Saturday.Bring gloves
We supply tools, water and snacks.Meet at the kiosk
We start at nine and finish by noon.
Quiet
One sentence on what it means for your visit.Shaded
One sentence on what it means for your visit.Level
One sentence on what it means for your visit.Open daily
One sentence on what it means for your visit.
import {
FeatureGrid,
FeatureGridBody,
FeatureGridCell,
FeatureGridHeading,
FeatureGridIcon,
FeatureGridLink,
FeatureGridList,
} from '@fairgarden-private/design/components/FeatureGrid'
import { Icon } from '@fairgarden-private/design/components/Icon'
import styles from './kinds.module.css'
const ways = [
{ icon: 'search', title: 'Find a trail', body: 'Search 40 preserves by distance, terrain and dogs allowed.' },
{ icon: 'download', title: 'Take the map', body: 'Download printable maps that work without a signal.' },
{ icon: 'help', title: 'Ask a steward', body: 'Our stewards answer questions within two days.' },
] as const
const steps = [
{ title: 'Pick a date', body: 'Crew days run every second Saturday.' },
{ title: 'Bring gloves', body: 'We supply tools, water and snacks.' },
{ title: 'Meet at the kiosk', body: 'We start at nine and finish by noon.' },
]
/** Icon (default), numbered, rule-topped and framed grids. */
export function FeatureGridKinds() {
return (
<div className={styles.stack}>
<FeatureGrid header={{ eyebrow: 'Visit', heading: 'Plan your walk' }}>
<FeatureGridList>
{ways.map((way) => (
<FeatureGridCell key={way.title}>
<FeatureGridIcon>
<Icon name={way.icon} size="block" />
</FeatureGridIcon>
<FeatureGridHeading>
<FeatureGridLink href="#kinds">{way.title}</FeatureGridLink>
</FeatureGridHeading>
<FeatureGridBody>{way.body}</FeatureGridBody>
</FeatureGridCell>
))}
</FeatureGridList>
</FeatureGrid>
<FeatureGrid kind="numbered">
<FeatureGridList>
{steps.map((step) => (
<FeatureGridCell key={step.title}>
<FeatureGridHeading>{step.title}</FeatureGridHeading>
<FeatureGridBody>{step.body}</FeatureGridBody>
</FeatureGridCell>
))}
</FeatureGridList>
</FeatureGrid>
<FeatureGrid kind="rule-topped">
<FeatureGridList>
{steps.map((step) => (
<FeatureGridCell key={step.title}>
<FeatureGridHeading>{step.title}</FeatureGridHeading>
<FeatureGridBody>{step.body}</FeatureGridBody>
</FeatureGridCell>
))}
</FeatureGridList>
</FeatureGrid>
<FeatureGrid kind="framed">
<FeatureGridList>
{['Quiet', 'Shaded', 'Level', 'Open daily'].map((title) => (
<FeatureGridCell key={title}>
<FeatureGridHeading>{title}</FeatureGridHeading>
<FeatureGridBody>One sentence on what it means for your visit.</FeatureGridBody>
</FeatureGridCell>
))}
</FeatureGridList>
</FeatureGrid>
</div>
)
}
On paper, forest and leaf
On paper, forest and leaf
glossary pairs small geometric drawings with caps captions. Pure line and type, the grid works on every ground; in saturated fields such as leaf, icons, numerals and drawings take the one ink. Keep grids in saturated fields to four cells of 40 words or fewer.
paper
Above
Higher than the trail.Around
A loop back to the lot.
forest field
Above
Higher than the trail.Around
A loop back to the lot.
leaf field
Above
Higher than the trail.Around
A loop back to the lot.
import {
FeatureGrid,
FeatureGridBody,
FeatureGridCell,
FeatureGridDrawing,
FeatureGridHeading,
FeatureGridList,
} from '@fairgarden-private/design/components/FeatureGrid'
import { Ground } from '@fairgarden-private/design/components/Ground'
import styles from './grounds.module.css'
/** A glossary grid: drawings in the ground's one ink, captions in caps. */
export function FeatureGridGrounds() {
return (
<div className={styles.row}>
<Ground kind="face" preset="paper" className={styles.face}>
<p className={styles.name}>paper</p>
<Glossary />
</Ground>
<Ground kind="field" preset="forest" className={styles.face}>
<p className={styles.name}>forest field</p>
<Glossary />
</Ground>
<Ground kind="field" preset="leaf" className={styles.face}>
<p className={styles.name}>leaf field</p>
<Glossary />
</Ground>
</div>
)
}
function Glossary() {
return (
<FeatureGrid kind="glossary">
<FeatureGridList>
<FeatureGridCell>
<FeatureGridDrawing>
<svg viewBox="0 0 64 64" strokeWidth="2">
<path d="M8 56 32 12l24 44z" />
</svg>
</FeatureGridDrawing>
<FeatureGridHeading>Above</FeatureGridHeading>
<FeatureGridBody>Higher than the trail.</FeatureGridBody>
</FeatureGridCell>
<FeatureGridCell>
<FeatureGridDrawing>
<svg viewBox="0 0 64 64" strokeWidth="2">
<circle cx="32" cy="32" r="22" />
</svg>
</FeatureGridDrawing>
<FeatureGridHeading>Around</FeatureGridHeading>
<FeatureGridBody>A loop back to the lot.</FeatureGridBody>
</FeatureGridCell>
</FeatureGridList>
</FeatureGrid>
)
}
API Reference
FeatureGrid
The feature grid module: an optional header (header, or a composed
FeatureGridHeader), then a FeatureGridList of 2–6 FeatureGridCells. Each cell holds one leader
(FeatureGridIcon or FeatureGridDrawing; numbered cells draw their own
numeral), a FeatureGridHeading (optionally wrapping a FeatureGridLink)
and a FeatureGridBody. Use one leader type per grid, never mixed.
| Prop | Type | Description |
|---|---|---|
header | | The module header (§11.8), rendered in the header slot before the
children: a |
kind | |
|
primary | | Primary Radix scale: numerals, headings, text, rules and the frame. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the block icons ( |
FeatureGridHeader and FeatureGridList
The module header slot: holds the §11.8 SectionHeader (FeatureGrid’s
header prop fills it for you); stays with the first cells in print.
The cells’ grid: a ul, or an ol for the numbered kind, whose order the
numerals carry. In the framed kind it sits inside the faced frame.
FeatureGridCell
One benefit: leader → heading → body. Numbered cells draw their
zero-padded numeral (“01″) first, from the list order. A cell with a
FeatureGridLink is linked as a whole.
FeatureGridIcon and FeatureGridDrawing
The block-icon leader: put an <Icon size="block" … /> (Material Symbols
Rounded, FILL 0) inside. It fills in --role-accent, which resolves to
--primary12 on saturated grounds. Never put a colored tile behind it.
The glossary leader: a small geometric drawing (inline SVG, spot size
--size-px-9) in --primary12. Fixed size; it never scales.
FeatureGridHeading, FeatureGridLink and FeatureGridBody
The cell’s heading: type-itemhead in --primary12; in the glossary kind
a type-label caps caption. Renders <h3>.
The cell’s one link, inside FeatureGridHeading: a §9.3 title Link whose
hit area stretches over the cell. Hover, focus and press underline the
heading; the cell draws the focus ring.
| Prop | Type | Description |
|---|---|---|
external | | Adds the arrow-open mark and “(external site)” for assistive technology.
Default |
index | | Adds the screen-only visited ✓ used in long indexes, such as reference
and archive lists. Default |
list | | With |
muted | | Rests in |
primary | | Primary Radix scale: the link text and focus ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the accent underline. Never defaulted; omitted, it inherits the scope. |
className | | Extra class names, added after the module’s own. |
A sentence or two of type-body-ui in --primary12.
Additional types
featureGrid
type featureGrid = featureGridFeatureGridBodyProps
Props for FeatureGridBody: div props and render.
type FeatureGridBodyProps = useRender.ComponentProps<'div'>FeatureGridCellProps
Props for FeatureGridCell: list-item props and render.
type FeatureGridCellProps = useRender.ComponentProps<'li'>FeatureGridDrawingProps
Props for FeatureGridDrawing: span props and render.
type FeatureGridDrawingProps = useRender.ComponentProps<'span'>FeatureGridHeaderProps
Props for FeatureGridHeader: header props and render.
type FeatureGridHeaderProps = useRender.ComponentProps<'header'>FeatureGridHeadingProps
Props for FeatureGridHeading: heading props and render (default <h3>).
type FeatureGridHeadingProps = useRender.ComponentProps<'h3'>FeatureGridIconProps
Props for FeatureGridIcon: span props and render.
type FeatureGridIconProps = useRender.ComponentProps<'span'>FeatureGridKind
The five cell constructions (§12.6).
type FeatureGridKind = 'icon' | 'numbered' | 'rule-topped' | 'framed' | 'glossary'FeatureGridLinkProps
Props for FeatureGridLink: Link props except kind, which is always title.
type FeatureGridLinkProps = {
/** Extra class names, added after the module's own. */
className?: string;
/**
* Primary Radix scale: the link text and focus ring. Never defaulted;
* omitted, it inherits the scope [D133].
*/
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
/**
* Secondary Radix scale: the accent underline. Never defaulted; omitted,
* it inherits the scope.
*/
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
/**
* With `kind="nav"`: a list link (nav-panel, footer, drawer and breadcrumb
* lists), whose hover is `--role-link-hover` color only, plus the
* `--ds-stroke-1-5` `--role-accent` underline where that ink is
* `--primary12`. Without it, `nav` is bare navigation text (bar and
* utility items, page numbers, toolbar links), whose hover is the
* `--border-size-2` `--role-accent` underline (§9.3) [D181]. Default
* `false`.
*/
list?: boolean | null;
/**
* Adds the screen-only visited ✓ used in long indexes, such as reference
* and archive lists. Default `false` [D174, D175].
*/
index?: boolean | null;
/**
* Adds the arrow-open mark and "(external site)" for assistive technology.
* Default `false`.
*/
external?: boolean | null;
/**
* Rests in `--role-muted` instead of `--primary12`, as a breadcrumb's
* ancestors. Hover takes `--role-link-hover` only (the underline is added
* where that ink is `--primary12`); with `kind="nav"` it replaces the bar
* item's bare-text underline (§9.3, §9.8) [D181]. Default `false`.
*/
muted?: boolean | null;
}FeatureGridListProps
Props for FeatureGridList: list props and render.
type FeatureGridListProps = useRender.ComponentProps<'ul'>FeatureGridProps
Props for FeatureGrid: section props, render, the kind and the color axes.
type FeatureGridProps = React.ClassAttributes<HTMLElement> &
React.HTMLAttributes<HTMLElement> &
__type & {
kind?: FeatureGridKind;
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
header?: React.ReactNode | SectionHeaderProps;
}Specification: DESIGN-SYSTEM.md §12.6 (feature grid) and §5.10.2 (module reflow).