Components / Structure
PageHeader
The top of a page or a major section: where you are (breadcrumbs or an eyebrow), what this is (the title), one or two sentences about it (the lead), and the page's actions. For the heading of a smaller block inside a page, use Heading on its own.
When to useLink to "When to use"
- The top of a page:
titlealone is enough. Adddescriptionwhen the page needs a sentence of explanation andactionsfor what the user can do with the whole page. - Where the page belongs:
breadcrumbswhen the trail can be followed,eyebrowwhen a short label is enough. With both, the breadcrumbs come first. - A major section of a long page:
headingLevel={2}or3withas="section"oras="div". - A landing page:
size="lg"withalign="center".
Use something else when:
- it is the title of a card, a panel or a small group: Heading, or Card for a card
- the area has no content yet: EmptyState, which also has a title, a description and actions
- it is a message about something that happened: Notice
UsageLink to "Usage"
import { Breadcrumbs, Button, PageHeader } from "@arshad-shah/cynosure";
<PageHeader title="Projects" />
<PageHeader
breadcrumbs={<Breadcrumbs items={[{ label: "Home", href: "/" }, { label: "Projects" }]} />}
eyebrow="Workspace"
title="Projects"
description="Every project in this workspace, newest first."
actions={<Button variant="solid" tone="accent">New project</Button>}
divider
/>Actions follow the header's widthLink to "Actions follow the header's width"
Beside the text, the actions sit at the inline end, level with the top of the title block, and take at most half the width. When the header itself is narrower than 36rem they move below the text and start from the start edge. This follows the header's own width, not the viewport, so it also works in a side panel or a narrow column.
Landing pagesLink to "Landing pages"
size="lg" renders the title at Heading's display size. align="center" centres every part and puts the actions below the text at any width.
Heading levels and dividerLink to "Heading levels and divider"
headingLevel sets the element (h1, h2 or h3). With size="md" the title takes Heading's usual size for that level: 2xl, xl and lg. divider draws a bottom border with space above it.
PropsLink to "Props"
| Prop | What it does | Type | Default |
|---|---|---|---|
titleRequired | What the page or section is. Rendered as the header's one heading. | ReactNode | |
headingLevel | Heading level of the title, to fit the page outline. Default 1. | 2 | 3 | 1 | 1 |
size | Size of the title. "md" is the usual size of the heading level (level 1 "2xl", level 2 "xl", level 3 "lg" in Heading's sizes); "lg" is the hero "display" size for a landing page. Default "md". | "md" | "lg" | "md" |
titleSize | Any of Heading's sizes for the title, instead of the one size gives: "3xl" sits between "md" (2xl at level 1) and "lg" (display), for a section's landing page. The level and the rest of the header are unchanged. | HeadingSize | |
eyebrow | A short label above the title that says where the page belongs. It comes before the title in reading order. | ReactNode | |
description | One or two sentences under the title, as a lead paragraph. Pass inline content only. | ReactNode | |
breadcrumbs | The trail to this page, shown above the eyebrow and the title. Pass a Breadcrumbs. | ReactNode | |
actions | The page's buttons. They sit at the inline end, level with the top of the title block, and move below the text when the header itself is narrower than 36rem or when align is "center". | ReactNode | |
meta | A row under the description for badges, dates and authors. It wraps. | ReactNode | |
children | Anything below the rest of the header, at full width: tabs, a search field. | ReactNode | |
align | "start" for pages; "center" centres the text and puts the actions below it, for landing pages. Default "start". | "start" | "center" | "start" |
divider | Draws a bottom border with space above it, to separate the header from the page. Default false. | boolean | false |
as | The element rendered. A header inside main is not a banner landmark, so no choice adds a landmark. Default "header". | "div" | "section" | "header" | "header" |
className | Added to the root element, for layout. | string | |
style | Layout only. Restyle through --cy-page-header-* tokens. | CSSProperties |
Generated from the type definitions in @arshad-shah/cynosure 0.5.0.
Behaviour and accessibilityLink to "Behaviour and accessibility"
PageHeader has no keyboard behaviour of its own. Tab moves through what you pass in, in reading order: breadcrumbs, actions, then children.
- One heading: the title is the header's only heading, at
headingLevel. The eyebrow and the description are paragraphs. - Reading order: breadcrumbs, eyebrow, title, description, meta, actions, children. The eyebrow is read before the title, as context for it.
- No landmark: the root has no role. A
headerelement insidemainis not a banner landmark. If the header is outsidemain,articleandsection, useas="div". - Built from Heading and Text: the title is a Heading, the eyebrow a Text with
variant="eyebrow"and the description a Text withvariant="lead", so their tokens apply here too. - Spacing: no outer margin or padding, and parts that are not given render nothing. A header with only a title is exactly as tall as its heading.
- Width: fills its parent. Nothing overflows at 320px: long words in the title break and the actions wrap.
- Line length: the description is at most 65ch wide.
- Right to left: the text starts on the right and the actions sit on the left.
TouchLink to "Touch"
PageHeader has nothing pressable of its own. The buttons, breadcrumbs and fields you pass in keep their own hit areas (at least 24px, 44px on coarse pointers). On a phone the header is narrower than 36rem, so the actions are below the text.
ThemingLink to "Theming"
Tokens: --cy-page-header-gap, --cy-page-header-text-gap, --cy-page-header-actions-gap, --cy-page-header-description-max-width, --cy-page-header-divider-color and --cy-page-header-divider-space.
| Token | What it sets | Default |
|---|---|---|
--cy-page-header-gap | Space between the breadcrumbs, the title block, the actions and the content below them | --cy-space-6 |
--cy-page-header-text-gap | Space between the eyebrow, the title, the description and the meta row | --cy-space-3 |
--cy-page-header-actions-gap | Space between two actions and between items of the meta row | --cy-space-4 |
--cy-page-header-description-max-width | Longest line of the description | 65ch |
--cy-page-header-divider-color | Colour of the bottom border drawn by divider | --cy-color-line |
--cy-page-header-divider-space | Space between the content and that border | --cy-space-6 |
createTheme({ components: { pageHeader: { textGap: "0.5rem", descriptionMaxWidth: "50ch" } } });The title, eyebrow and lead are retuned through the --cy-heading-* and --cy-text-* tokens. The 36rem switch is fixed, because a container query cannot read a token. className and style are for layout only (margin, placement, width).
RelatedLink to "Related"
Heading · Text · Breadcrumbs · EmptyState · Button
These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.