GridList

Molecule
Tiled card grids for people directories, item collections, and image galleries.

Playground

Every control sets a real prop of GridListProps. The JSX below updates as you go.
  • RC
    Rachel Chen
    Engineering Lead
    Active
  • AL
    Ada Lovelace
    Staff Engineer
    Active
  • KT
    Kevin Turner
    Product Designer
    Away
Props
Columns
pick one
compact
boolean
JSX · GridListProps
<GridList cols3 />

Variants

2 examples from src/molecules/grid-lists/grid-lists.md, each rendered live from its own JSX.
  • hero-banner.png
    1.2 MB
  • icon-set.svg
    340 KB
  • product-shot.jpg
    2.8 MB
Gallery
<GridList
gallery
cols3
items={[
{ title: "hero-banner.png", subtitle: "1.2 MB", color: "primary" },
{ title: "icon-set.svg", subtitle: "340 KB", color: "blue-500" },
{ title: "product-shot.jpg", subtitle: "2.8 MB", color: "emerald-500" }
]}
/>
Tappable
onPressItem makes every tile a button and reports the pressed index.
<GridList
onPressItem={() => {}}
items={[
{ title: "Rachel Chen", subtitle: "Engineering Lead", avatar: "RC" },
{ title: "Ada Lovelace", subtitle: "Staff Engineer", avatar: "AL" },
{ title: "Kevin Turner", subtitle: "Product Designer", avatar: "KT" }
]}
/>

Anatomy

  • RC
    Rachel Chen
    Engineering Lead
    Active
  • AL
    Ada Lovelace
    Staff Engineer
    Active
  • KT
    Kevin Turner
    Product Designer
    Away
1
Grid
2
Tile
3
Media
4
Caption
Dimmed parts appear only in some states or variants.

Props

10 props on GridListProps, grouped as they are declared in source. Required props are marked *.
Prop
Type
Default
Description
Props
1 prop
items *
GridListItem[]
–
The tiles to render, one card per entry.
Columns
pick one
3 props
cols3
boolean
false
cols2
boolean
false
gallery
boolean
false
Gallery mode: render each tile as a borderless thumbnail (a square color block from item.color, with a left-aligned filename and size below). Avatars, badges, and actions are not shown in this mode. Omit for the default people/card tile.
Density modifier
6 props
compact
boolean
false
onPressItem
(index: number) => void
–
Make each tile a tappable target (open a detail, select a tile). When set, every tile renders as a Pressable with a button role and a pressed affordance, so a tappable grid needs no hand-rolled Pressable.
label
string
–
The grid's accessible name (e.g. "Team members"): a screen reader announces it with the list of tiles. A virtualized grid needs one: on the web its scroller is a keyboard stop while the tiles overflow, and Chromium names an unnamed stop from the text of every tile it has rendered.
virtualized
boolean
false
Render the tiles through a windowed FlatList instead of mounting every tile up front, for large grids. Give the grid a bounded height (via style, e.g. { maxHeight: 480 }) so it can scroll; without one it warns and renders eagerly anyway. Default (omitted) mounts all tiles, unchanged. On the web, while the tiles overflow, the windowed grid is a keyboard tab stop the keyboard can scroll, and it draws the focus ring around itself while it has keyboard focus.
testID
string
–
E2E hook forwarded to the root element.
style
LayoutStyle
–
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.

Accessibility and keyboard

Keyboard
Tab
Moves between links
Enter
Follows the link
Semantics
Roles
button
Below the platform minimum, the touch area grows to 44 pt on iOS and 48 dp on Android without moving the layout.
From the docs
The tiles are a list, as in Tailwind UI, and each tile is one of its items: a screen reader announces the list with its number of tiles and moves through it tile by tile. A tappable tile is a button inside its item. The label prop names the list (for example "Team members").
A virtualized grid with a bounded height scrolls its tiles on its own. On the web, while those tiles overflow, the grid is a keyboard tab stop (before the tiles themselves when onPressItem or tile actions make them buttons), the keyboard can scroll it, and while it has keyboard focus the grid, which has no card around it, draws the theme's focus ring around itself. Only the tiles near its viewport are mounted, and each says where it sits in the whole grid, so a screen reader still counts every tile. Give a wind

Platform skins

The playground's props on each platform: same tree, native shapes, type and touch sizes.
  • hero-banner.png
    1.2 MB
  • icon-set.svg
    340 KB
  • product-shot.jpg
    2.8 MB
Web
control 10 · field 10 · card 16 · Instrument Sans
  • hero-banner.png
    1.2 MB
  • icon-set.svg
    340 KB
  • product-shot.jpg
    2.8 MB
iOS
capsule controls · field 8 · card 12 · SF Pro · 44 pt
  • hero-banner.png
    1.2 MB
  • icon-set.svg
    340 KB
  • product-shot.jpg
    2.8 MB
Android
Material 3 stadium · field 4 · card 12 · Roboto · 48 dp

Usage

Each tile action carries its own onPress, so every button on a card fires your handler.
<GridList
items={[
{ title: "Rachel Chen", subtitle: "Engineering Lead", avatar: "RC", badge: "Active", actions: [{ label: "Message", outline: true, onPress: () => {} }] },
{ title: "Ada Lovelace", subtitle: "Staff Engineer", avatar: "AL", badge: "Active", actions: [{ label: "Message", outline: true, onPress: () => {} }] },
{ title: "Kevin Turner", subtitle: "Product Designer", avatar: "KT", badge: "Away", actions: [{ label: "Message", outline: true, onPress: () => {} }] }
]}
/>
The tiles are a list, as in Tailwind UI, and each tile is one of its items: a screen reader announces the list with its number of tiles and moves through it tile by tile. A tappable tile is a button inside its item. The label prop names the list (for example "Team members").
A virtualized grid with a bounded height scrolls its tiles on its own. On the web, while those tiles overflow, the grid is a keyboard tab stop (before the tiles themselves when onPressItem or tile actions make them buttons), the keyboard can scroll it, and while it has keyboard focus the grid, which has no card around it, draws the theme's focus ring around itself. Only the tiles near its viewport are mounted, and each says where it sits in the whole grid, so a screen reader still counts every tile. Give a windowed grid a label: focused, a list with no name is named in Chromium from the text of every tile it has rendered, so the kit warns in development when it has none.

Tokens

Read from the playground render. Values follow the scheme and the ion hue.
--fd
--ft
--ion-soft
--ion-tx
--ln
--sf
--tx3

Related components