Design system/Components
Page header
PageHeader heads every page in the app: the title on its own line, one line of description below it, and actions in a separate row. Stacking is what lets a long title and a full row of buttons live together.
In codecomponents/page-header.tsxcomponents/app-header.tsx
Live example
Every page used to write this by hand, and the versions drifted apart: the title shared a line with up to five buttons, so in a narrow window the very name of the thing you were looking at got squeezed.
My network
People you know and their follow-ups.
Anatomy
- leadingAn icon, avatar, or emoji before the title.
- TitleThe name of what you're looking at; it wraps and isn't truncated.
- trailingOne action that goes beside the name, not below it; on phones it moves under the text unless trailingInline.
- AboutOne line, 12.5 to 13px.
- ActionsA row of 42px pills; on phones they split the line evenly.
Sizes
25px → 19pxPhone → desktop27px → 21pxSettings and admin30px → 24pxDashboardRules
Do
Put buttons in actions and let the row lay itself out.
Don't
Title and buttons in one flex; the title is the first thing to get squeezed.
Do
A title that isn't plain text should get barTitle.
Don't
The top bar stays nameless because the title was a ReactNode.
Do
A main action that depends on the user's role uses useHeaderAction.
Don't
Hard-coding the main action in the top bar based on the route.
<PageHeader
title={tr("شبکه من")}
description={tr("آدمهایی که میشناسی و پیگیریهایشان.")}
actions={
<>
<button className="btn btn-dark" onClick={add}><Icon d={paths.userPlus} size={15} />{tr("آدم جدید")}</button>
<Link href="/opportunities" className="btn btn-ghost">{tr("فرصتها")}</Link>
</>
}
/>Sizes, precisely
font-semibold 600 · leading-tightoverflow-wrap: anywhere12.5px · --text-secondary · mt 2px13pxOne line · ellipsisFull text in titleMulti-line · line-height 1.75mt 12px · gap 8px · flex-wrap42px · padding-inline 14px 18px · 13.5px / 600Icon 15px · gap 7pxflex: 1 1 auto · centeredgap 12pxPhone: trailing full-width · mt 10px≥ 900px · body[data-hdr-title]Visible again in printAccessibility and direction
- The title is an <h1>, even when it's hidden on desktop and the app header shows the name; with display: none it also leaves the accessibility tree, so the app header must carry the same name.
- The description is --text-secondary: 4.72 to 1 on the light background and 6.32 in dark, AA in both.
- trailing is on the left in right-to-left and on the right in left-to-right; with flex and no directional rule.
Do
At most three pills on phones; they share the line.
Don't
Five pills that turn into three lines at 360px.
Related pages