Page
The page vocabulary under a pane's toolbar. A flush intro line, the config grid of sections in one column or two, the picture gallery and the plain stack, with no page column, so every page fills its pane edge to edge.
Output
Installation
$ pnpm dlx shadcn@latest add @videorc/pageUsage
import {
CONFIG_GRID_PAIR,
ConfigGrid,
Gallery,
PageHeader,
PageStack,
} from "@/components/page";<PaneBody className="@container/page">
<PageHeader
description="Quality for recordings and livestreams on this computer."
title="Output"
/>
<ConfigGrid>
<PanelSection title="Recording">…</PanelSection>
<PanelSection title="Livestream">…</PanelSection>
</ConfigGrid>
</PaneBody>Pages compose these instead of hand-rolling grids. A page follows its own width, never the window's: the pane body around it is a container, @container/page, and 940 px of it is the one layout breakpoint (a 1,024 px viewport counted the 208 px sidebar as page and squeezed two columns into 816 px). A form's own sub-grid uses sm and md.
| Archetype | Pages | Built with |
|---|---|---|
| Config grid | Sources, Livestream, Output, Settings | A ConfigGrid of Panel Sections: one column, two from 940 px of page |
| Stack | One section, or a tab | A PageStack of Panel Sections |
| Gallery | Assets, Screens | A Gallery of picture cards |
| Browse | Library | A flush list or table in the pane body |
| Stage, Bench, Inspect | Studio, Scene, Health | Bespoke |
Don't add a max-width column or a hand-rolled grid. Don't put a page's actions in the toolbar either: they go at the end of the PageHeader's line, or in a section's header.
Examples
Gallery
Cards are only for objects with a picture: backgrounds, scenes, Buddies, library items. A Gallery fills its tracks by the width it has. dense packs 10 rem cards, for a picker inside a dialog. rowsOfFive holds a row to five cards, which may shrink to 11 rem so five fit the default window: ten cards read as two rows of five.
Two sections that fill the height
A tab of exactly two sections passes CONFIG_GRID_PAIR to its ConfigGrid. In two columns the grid fills the visible height, so the hairline between the columns runs the full height however short the tab is. Stacked, the rows keep their content height. The preview above does this.
Theming
| Token or attribute | Meaning |
|---|---|
px-gutter | The PageHeader's 16 px sides |
@container/page | The pane body the page sits in: the width the grid follows |
@min-[940px]/page:grid-cols-2 | The config grid's two columns |
@min-[940px]/page:[&>*:nth-child(odd)]:border-r | The hairline between the columns |
CONFIG_GRID_PAIR | flex-1 content-start @min-[940px]/page:content-stretch @min-[940px]/page:[&>*]:border-b-0 |
data-slot | page-header, config-grid, gallery, page-stack |
Accessibility
The toolbar already shows the page's name as its h1, so PageHeader's title is a visually hidden h2 for assistive tech. Its description is plain text. A Gallery is only a grid: give it an aria-label, and make each card a button, with aria-pressed when the gallery is a choice.
API reference
PageHeader
Prop
Type
ConfigGrid and PageStack
Prop
Type
Gallery
Every div attribute, plus:
Prop
Type
Pane
The flush column every page lives in. A 40 px toolbar with the page title on the window's drag band, a body that's the only thing that scrolls, and a strip pinned under the toolbar for tabs or filters.
Page Tabs
A page with tabs. One segmented tab list pinned in a strip under the toolbar, and only the region under it scrolls. The selected tab is the caller's, so the app can remember it and open a named tab from a link.