Source: https://monarchui.dev/components/page-header/

Patterns · Layout

# PageHeader

Top of a main view: the single h1, back link or breadcrumbs, status, details, page actions with overflow, and tabs.

@rookcom/monarch-react

Pattern

## With breadcrumb, status and actions

## Usage examples

### Publishable entity: back link, status, address and overflow actions

### With section tabs

## Purpose

Lays out the top of every main view: an optional banner, back link and breadcrumbs, the page’s h1 with status and meta, a details line and description, page-level actions (a primary action plus secondary actions that collapse into a "More actions" menu), and section tabs.

### Use when

- At the top of each main view, once per page.
- A publishable entity (a page, a domain, a form) needs its status, address and Publish action in one row.
- A page embedded in another shell (App Settings) still needs its heading: use `embedded`.

### Avoid when

- Headings for sections inside a page: use SectionHeader, SectionCard or SettingsSection.
- The header of one record (a contact, a ticket): use RecordHeader, which adds an avatar, facts and prev/next.
- Dialogs and panels: they have their own headers.

## Design principles

- One h1 per page: `title` always renders as the heading (`h1` unless `headingLevel="h2"`).
- Actions in the header apply to the whole page; keep one primary action and let the rest overflow.
- Slots, not settings: banner, back, breadcrumbs, status, meta, details, actions and tabs take any nodes.
- Responsive by CSS alone: the server and the client render the same markup at every width.
- Print-friendly: actions and tabs are hidden when printing.

## API reference

```tsx
import { PageHeader } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `PageHeader` | component | server-safe | `.mn-page-header-sticky-top` |

Renders a `<header>`, forwards its ref and passes native attributes through.

Server-safe: the header has no state. Only the overflow menu (a DropdownMenu) is a client component; `secondaryActions` with `onSelect` must come from a client component, `href` actions work from server components.

`PageHeaderAction` is `{ id, label, icon?, onSelect?, href?, disabled?, tone? }`.

CSS variables: `--mn-page-header-sticky-top` (sticky offset, default 0) and `--mn-page-header-padding-inline` (inline padding, for example the icon-rail offset, default 0).

Generated from the TypeScript declarations of `packages/react/src/patterns/layout/page-header`.

## Properties

### `PageHeader`

Top of every main view: title, context, and the actions that apply to the whole page. Server-safe; only the overflow menu is a client component.

| Prop | Type | Description |
| --- | --- | --- |
| `title` required | `ReactNode` | Page title, rendered as the page's single h1. |
| `actions` | `ReactNode` | Primary and secondary actions. Keep one `primary` Button. |
| `back` | `ReactNode` | A back link above the title: any node (usually a BackLink with `asChild` around a router link). Takes precedence over `backHref`. |
| `backHref` | `string` | Renders a BackLink to this URL above the title. Use `back` for router links. |
| `backLabel` | `ReactNode` | Text of the `backHref` link, naming the destination ("All domains"). Default "Back". |
| `banner` | `ReactNode` | A notice above the header (an Alert or CalloutBanner), for example "This page is archived". |
| `breadcrumbs` | `ReactNode` | A Breadcrumb above the title. Rendered before `eyebrow` when both are given. |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `description` | `ReactNode` |  |
| `details` | `ReactNode` | A secondary line under the title: an address with a CopyButton, an id, "Updated 5 min ago". Rendered before `description`. |
| `embedded` | `boolean` | For a page embedded in another shell (App Settings): the title becomes visually hidden but stays the heading, and the outer padding is removed. |
| `eyebrow` | `ReactNode` | Breadcrumb or eyebrow text above the title. |
| `headingLevel` | `"h2" \| "h1"` | Heading element. `h1` (default) for a page; `h2` when embedded under another h1. |
| `id` | `string` |  |
| `maxVisibleActions` | `number` | How many secondary actions show as buttons on wide screens. Default 2. |
| `meta` | `ReactNode` | Badge or status next to the title. |
| `moreActionsLabel` | `string` | Accessible name of the overflow menu button. Default "More actions". |
| `primaryAction` | `ReactNode` | The page's main action, placed last in the action row. Stays visible at every width. |
| `secondaryActions` | `PageHeaderAction[]` | Secondary actions as data. The first `maxVisibleActions` show as buttons on wide screens and the rest go into a "More actions" menu. Below 640px all of them move into the menu. |
| `status` | `ReactNode` | A status badge next to the title, before `meta` (Published, Draft, Active). |
| `sticky` | `boolean` | Stick to the top of the scroll container with a blurred backdrop. The offset is `--mn-page-header-sticky-top` (default 0). |
| `tabs` | `ReactNode` | A TabsList or TabsNav for section navigation below the title. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `banner / back / breadcrumbs / eyebrow / status / meta / details / actions / tabs` | `'omitted'``'provided'` | Each slot renders its wrapper only when provided, in that order from the top. |
| `secondaryActions + maxVisibleActions` | `'0'``'1'``'2 (default)'``'n'` | How many secondary actions show as buttons from 640px; the rest are in the More menu. Below 640px all are in the menu. |
| `sticky` | `'false'``'true'` | Sticks to the top of the scroll container with a blurred, slightly translucent canvas background and a bottom border. Exposed as `data-sticky`. |
| `embedded` | `'false'``'true'` | Hides the title visually (it stays the heading for screen readers) for a page inside another shell. Exposed as `data-embedded`. |
| `headingLevel` | `'h1'``'h2'` | The heading element. Default `h1`. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Static | – | The header has no state; slot content owns its states. |
| Overflowing actions | `data-overflow on the More button` | Set when more secondary actions exist than `maxVisibleActions`; without it the More button only shows below 640px. |
| Disabled action | – | A disabled action is a disabled button, and a disabled menu item (`aria-disabled`); a disabled `href` action renders as a button so it cannot be followed. |

## Interaction behaviour

- Secondary action buttons call `onSelect` or follow `href`.
- The More button opens a menu with every secondary action; on wide screens the items already shown as buttons are hidden from it.
- Choosing a menu item calls its `onSelect` (or follows its link), closes the menu and returns focus to the More button.

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab | Moves through back link, breadcrumbs, actions and tabs in reading order. |
| Enter / Space / ArrowDown | On the More button, opens the menu. |
| ArrowUp / ArrowDown | Moves between menu items. |
| Escape | Closes the menu and returns focus to the More button. |

## Accessibility

Role

banner landmark only when it is not inside main, article or section (native <header> rules)

Accessible name

The heading is the page’s main heading.

- `title` renders as the h1, so screen-reader heading navigation lands on it; with `embedded` it is visually hidden, not removed.
- Pass a Breadcrumb in `breadcrumbs` for the navigation landmark and current-page marking.
- The More button is an icon button with a required name; give it the object: `moreActionsLabel="More actions for Website refresh"`.
- Actions keep visible text labels; icons in actions are decorative.
- The live examples on this page render with `headingLevel="h2"` because the docs page has its own h1; in an app use the default h1.

## Responsive behaviour

- The title block and the actions sit in a wrapping row; actions move under the title when space runs out.
- Below 640px secondary actions collapse into the More menu, so at 320px the row holds the primary action and one icon button.
- Long titles and details wrap anywhere instead of overflowing.
- The description is limited to `--mn-layout-reading-max` for readable line length.

## Theme support

- Title and muted text use Monarch typography and colour tokens, so every theme applies.
- The sticky backdrop mixes the canvas token with transparency; with `prefers-contrast: more` or without backdrop-filter support it is solid.

## Do and don't

### Do

- Use exactly one PageHeader per page.
- Keep a single primary action; put the rest in `secondaryActions` so they collapse on phones.
- Name the More button after the page when several menus share a screen.

### Don't

- Do not add another h1 elsewhere on the page.
- Do not put row- or section-level actions in the page header.
- Do not pass `onSelect` callbacks from a server component; use `href` actions there.

## Related components

- [Breadcrumb](https://monarchui.dev/components/breadcrumb/): The usual `breadcrumbs` content.
- [BackLink](https://monarchui.dev/components/back-link/): The `back` slot, or built for you by `backHref`.
- [Tabs](https://monarchui.dev/components/tabs/): Section navigation in the `tabs` slot (TabsNav for routes).
- [RecordHeader](https://monarchui.dev/components/record-header/): Header for one record: avatar, facts, prev/next.
- [Toolbar](https://monarchui.dev/components/toolbar/): List tools that sit under the header.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `react` |
| Monarch components | [BackLink](https://monarchui.dev/components/back-link/), [Button](https://monarchui.dev/components/button/), [DropdownMenu](https://monarchui.dev/components/dropdown-menu/) |

The sticky backdrop uses `--mn-z-sticky` and `--mn-color-bg-canvas`.

## Testing coverage

- Renders the title as the single h1 with actions.
- Renders banner, back link, breadcrumbs, status, details and primary action in order.
- A custom `back` node wins over `backHref`.
- Shows the first secondary actions as buttons and lists every action in the More menu, marking the inline ones; keyboard selection calls `onSelect` and returns focus.
- Keeps the More button for narrow screens when every action fits; disabled actions are disabled in both places.
- Embedded mode hides the heading visually; `headingLevel` changes the level.
- Sticky mode, ref forwarding and native attributes.
- Renders on the server.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/page-header; Cross-browser axe: /components/page-header |

Tests: `packages/react/src/patterns/layout/page-header`

## All example code

### With breadcrumb, status and actions

```tsx
import { Badge, Breadcrumb, Button, PageHeader } from '@rookcom/monarch-react';

<PageHeader
  headingLevel="h2"
  eyebrow={
    <Breadcrumb
      items={[
        { label: 'Projects', href: '#/components/page-header' },
        { label: 'Website refresh' },
      ]}
    />
  }
  title="Website refresh"
  meta={<Badge tone="success">Active</Badge>}
  description="Tasks, owners and dates for this project."
  actions={
    <>
      <Button>Share</Button>
      <Button variant="primary">New task</Button>
    </>
  }
/>
```

### Publishable entity: back link, status, address and overflow actions

```tsx
import { Badge, BackLink, Button, CopyButton, PageHeader } from '@rookcom/monarch-react';

// TrashIcon: demo icon from the docs site; use your own.

<PageHeader
  headingLevel="h2"
  back={<BackLink href="#/components/page-header">All pages</BackLink>}
  title="Spring launch"
  status={<Badge tone="success">Published</Badge>}
  details={
    <>
      <span>launch.example.com/spring</span>
      <CopyButton
        value="https://launch.example.com/spring"
        iconOnly
        size="xs"
        label="Copy address"
      />
      <span>Updated 5 minutes ago</span>
    </>
  }
  secondaryActions={[
    { id: 'preview', label: 'Preview', href: '#/components/page-header' },
    { id: 'duplicate', label: 'Duplicate', onSelect: () => {} },
    { id: 'unpublish', label: 'Unpublish', onSelect: () => {} },
    {
      id: 'delete',
      label: 'Delete page',
      icon: <TrashIcon />,
      tone: 'danger',
      onSelect: () => {},
    },
  ]}
  moreActionsLabel="More actions for Spring launch"
  primaryAction={<Button variant="primary">Publish changes</Button>}
/>
```

### With section tabs

```tsx
import { Button, PageHeader, TabsLink, TabsNav } from '@rookcom/monarch-react';

// PlusIcon: demo icon from the docs site; use your own.

<PageHeader
  headingLevel="h2"
  title="Billing"
  description="Plan, invoices and payment methods."
  primaryAction={
    <Button variant="primary" leadingIcon={<PlusIcon />}>
      Add payment method
    </Button>
  }
  tabs={
    <TabsNav aria-label="Billing sections">
      <TabsLink href="#/components/page-header" active>
        Overview
      </TabsLink>
      <TabsLink href="#/components/page-header">Invoices</TabsLink>
      <TabsLink href="#/components/page-header">Payment methods</TabsLink>
    </TabsNav>
  }
/>
```
