Page
The page frame every screen uses: top bar (title, count, page actions) → view toolbar → summary → content.
When to use
- Every page. Wrap the app shell in PageProvider with one PageBar; each page renders <Page> with a <PageHeader>.
- Lists: PageHeader count + ViewToolbar (search, filters, view switch) + optional PageSummary.
- Forms, settings, documents: <Page width="narrow">.
- Boards, tables, split views: <Page bleed fill>. Kit headers/toolbars/summaries keep the gutter; custom chrome uses PageInset.
Consider an alternative
- A second h1 in the body — the bar's title is the page's only h1.
- Repeating the item count in the body (it's the count badge) or putting view switches in PageHeader (they go in ViewToolbar).
- Route-owned padding or containers: PageContent owns the single 16px / md:24px inset, and Page owns gap-4.
Import
import { Page } from '@revido-llc/kit';Props
Props documented by the Kit. Refer to the TypeScript types for the complete interface, including inherited props.
Related exports
PageBar, PageHeader, PageTitle, PageProvider, PageContent, PageInset, PageSummary, PageCount
Examples
List page
PageBar + Page: the title and count become the bar's h1; page actions are labelled buttons in the bar wherever the sidebar shows (md+) and collapse to a '+' (primary) and a ⋯ menu next to the title on phones. Layout, grouping and ordering live in one Display control in the ViewToolbar; metrics in PageSummary.
// app shell, once
<PageProvider>
<PageBar crumbs={crumbsFromRoute} leading={<SidebarTrigger />} trailing={<AppControls />} />
<PageContent>{children}</PageContent>
</PageProvider>
// a page
<Page>
<PageHeader
title="Deals"
count={deals.length}
secondaryActions={[{ label: "Export", icon: <Download />, onPress: exportCsv }]}
primaryAction={{ label: "New deal", onPress: openNewDeal }}
/>
<ViewToolbar aria-label="Deal filters" filters={<FilterChips fields={fields} value={filters} onChange={setFilters} />} display={<DisplayOptions layouts={layouts} orderings={orderings} value={display} defaultValue={defaults} onChange={setDisplay} />}>
<SearchField aria-label="Search deals" value={query} onChange={setQuery} />
<FilterButton fields={fields} value={filters} onChange={setFilters} />
</ViewToolbar>
<PageSummary items={[{ value: "€48,000", label: "pipeline" }, { value: "€21,300", label: "forecast", tone: "primary" }]} />
<DealList deals={deals} />
</Page>Narrow page (settings, forms)
<Page width="narrow">
<PageHeader title="Profile" primaryAction={{ label: "Save", icon: <Check />, onPress: save }} />
<TextField label="Name" />
</Page>Full-bleed board
The board scrolls to the panel edges while the toolbar stays aligned with the PageBar. Use PageInset only for custom chrome or panes inside a bleed view; ordinary pages inherit the shell gutter.
<PageContent>
<Page bleed fill>
<PageHeader title="Delivery" primaryAction={{ label: "New task" }} />
<ViewToolbar aria-label="Delivery filters"><SearchField aria-label="Search tasks" /></ViewToolbar>
<Board />
<PageInset>Custom footer</PageInset>
</Page>
</PageContent>Literal anatomy 1
Static component anatomy; bind events in the consuming app.
<PageProvider><PageBar crumbs={[{ label: "Drafts" }]} /><PageContent><Page><PageHeader title="Drafts" count={1} /><PageSummary items={[{ label: "Ready", value: "1" }]} /><PageInset>Draft proposal</PageInset></Page></PageContent></PageProvider>Literal anatomy 2
Static component anatomy; bind events in the consuming app.
<PageTitle title="Drafts" count={1} />Literal anatomy 3
Static component anatomy; bind events in the consuming app.
<PageCount title="Drafts" count={1} />Long record title
A narrow record frame preserves the full title on pointer hover and keyboard focus.
<PageProvider>
<PageBar crumbs={[{ label: "Projects", href: "/projects" }, { label: record.name }]} />
<PageContent><Page><PageHeader title={record.name} /></Page></PageContent>
</PageProvider>