KQ-1565 · YEARBOOK/GRID
Yearbook Grid
A yearbook page of drawn portraits where the face under the pointer or keyboard focus grows by widening its whole column and deepening its whole row: the grid's tracks are fractions driven by where the focus is — two motion values gliding cell to cell on springs.glide — and how open it is, so the page flexes like a table and every line stays in register instead of one picture bulging like a lens. Portraits are anchored at the foot, so a wider cell shows more shoulder and a taller one more room above the head, and where the open row and column cross the name and role print in left to right with a rule drawn under them. It is a real grid: arrow keys move cell by cell, Home and End go to the row's ends (Ctrl for the first and last), and Enter, Space or a click pins someone open.
Gaugeworks · the team, 2026
24 people
resting · point at a face
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/yearbook-grid
Props
- people
- YearbookPerson[]
- default defaultYearbookPeople
- The people, in reading order: { name, role, src?, alt?, art? }.
- value / defaultValue
- number | null
- default null
- The pinned person, whose row and column stay open when the pointer leaves; controlled or initial.
- onValueChange
- (index: number | null) => void
- default —
- Fires from the click or key that pinned or unpinned someone.
- onFocusChange
- (index: number | null) => void
- default —
- Fires as the face in focus changes, or null when the grid rests.
- zoom
- number
- default 2.2
- How far the focused column widens and its row deepens, as a multiple of a track, 1.2 to 3.
- gap
- number
- default 4
- The gutter between portraits, px.
- grain
- number
- default 0.4
- Paper grain and halftone over the portraits, 0 to 1; the face in focus prints cleaner.
- columns
- number
- default —
- A fixed number of columns; by default chosen from the width so the grid fits `maxHeight` with the fewest empty places.
- ratio
- number
- default 0.8
- Portrait width over height.
- maxHeight
- number
- default 520
- The tallest the grid may be, px; more columns are used to stay under it.
- ink
- string
- default "var(--foreground)"
- The dark ink of the print: backdrops and halftone.
- paper
- string
- default "var(--card)"
- The paper the page is printed on.
- captionHeight
- number
- default 34
- Room the deepened row makes for the name and role, px.
- label
- string
- default "Team"
- The grid's accessible name.
- disabled
- boolean
- default false
- Stops focus from opening the grid and pinning.
- className
- string
- default —
- Classes for the outer wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
| people | YearbookPerson[] | defaultYearbookPeople | The people, in reading order: { name, role, src?, alt?, art? }. |
| value / defaultValue | number | null | null | The pinned person, whose row and column stay open when the pointer leaves; controlled or initial. |
| onValueChange | (index: number | null) => void | — | Fires from the click or key that pinned or unpinned someone. |
| onFocusChange | (index: number | null) => void | — | Fires as the face in focus changes, or null when the grid rests. |
| zoom | number | 2.2 | How far the focused column widens and its row deepens, as a multiple of a track, 1.2 to 3. |
| gap | number | 4 | The gutter between portraits, px. |
| grain | number | 0.4 | Paper grain and halftone over the portraits, 0 to 1; the face in focus prints cleaner. |
| columns | number | — | A fixed number of columns; by default chosen from the width so the grid fits `maxHeight` with the fewest empty places. |
| ratio | number | 0.8 | Portrait width over height. |
| maxHeight | number | 520 | The tallest the grid may be, px; more columns are used to stay under it. |
| ink | string | "var(--foreground)" | The dark ink of the print: backdrops and halftone. |
| paper | string | "var(--card)" | The paper the page is printed on. |
| captionHeight | number | 34 | Room the deepened row makes for the name and role, px. |
| label | string | "Team" | The grid's accessible name. |
| disabled | boolean | false | Stops focus from opening the grid and pinning. |
| className | string | — | Classes for the outer wrapper. |