Skip to Content

Page Header

The page header is a fixed or sticky bar at the top of the page that holds page-level elements such as titles, tabs, breadcrumbs, and actions. It acts as a container with consistent padding and provides leftContent and rightContent render props that receive a breakpoint argument for responsive behavior.

Loading...

Overview

Resources

Loading...

Loading...

Loading...

Loading...

Install

yarn add @camp/page-header

Usage

The PageHeader component is a semantic <header> with two slots: leftContent and rightContent. Each slot receives a render function that gets the current breakpoint ('small' | 'medium' | 'large'), so you can show different layouts per viewport.

Basic example

Wrap the header (and any tab-driven content) in Tabs when using TabLists so the selected tab state is shared:

import { Tabs } from '@camp/tabs'; import { PageHeader } from '@camp/page-header'; import { LeftContent } from './LeftContent'; import { RightContent } from './RightContent'; <Tabs value={value} onValueChange={setValue}> <PageHeader leftContent={LeftContent} rightContent={RightContent} /> {/* page content that may use tab context */} </Tabs>;

Left and right content

Left and right content can be any React nodes. Typical patterns:

  • Left: Title (Text as h1), tabs (TabLists / TabTrigger), or breadcrumbs (Breadcrumbs) with optional actions (e.g. IconButton).
  • Right: Primary/secondary actions (Button), status text, or an overflow menu (IconButton with icon).

Example left content with title and tabs:

import { TabLists, TabTrigger } from '@camp/tabs'; import { Text } from '@camp/text'; export const LeftContent = ({ breakpoint }: { breakpoint: 'small' | 'medium' | 'large' }) => ( <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: '12px' }}> <Text appearance="heading-small" as="h1" color="default"> Campaigns ({breakpoint}) </Text> <TabLists> <TabTrigger value="tab1">Tab 1</TabTrigger> <TabTrigger value="tab2">Tab 2</TabTrigger> <TabTrigger value="tab3">Tab 3</TabTrigger> </TabLists> </div> );

Example right content with responsive behavior:

import { Button } from '@camp/button'; import { IconButton } from '@camp/icon-button'; import { MoreMenuMedium } from '@camp/icon'; export const RightContent = ({ breakpoint }: { breakpoint: 'small' | 'medium' | 'large' }) => { switch (breakpoint) { case 'small': return ( <div> <IconButton> <MoreMenuMedium title="More options" /> </IconButton> </div> ); default: return ( <div> <Button>Button</Button> </div> ); } };

Responsive breakpoints

Use the breakpoint argument in leftContent and rightContent to render different UI by viewport (e.g. icon-only actions on small, full buttons on large). A switch on breakpoint keeps the logic clear.

Position

Control layout with the position prop:

  • sticky (default): Header stays at the top while the page scrolls.
  • relative: Header scrolls with the page.

See the Variations section for examples.

Best practices

  • Use a single, clear page title in the left area (e.g. with Text as h1).
  • Prefer tabs or breadcrumbs in the left slot when the page has clear sections or hierarchy.
  • On small breakpoints, collapse multiple actions into a single menu (e.g. IconButton with MoreMenuMedium) instead of multiple buttons.
  • Use PageHeaderPipeSeparator from @camp/page-header between status text and actions when you need a visual divider in the right slot.

Content guidelines

✅ DO

  • Use a clear, concise page title * Keep primary actions visible on the right * Use breakpoint to simplify the header on small screens

🚫 DON’T

  • Do not overload the header with too many actions * Do not use the header for non-page-level controls

Variations

Position: sticky

Sticky positioning keeps the header fixed to the top while content scrolls underneath.

import { PageHeader } from '@camp/page-header'; import { LeftContent } from './LeftContent'; import { RightContent } from './RightContent'; <PageHeader position="sticky" leftContent={LeftContent} rightContent={RightContent} />;

Position: relative

Relative positioning lets the header scroll with the page.

import { PageHeader } from '@camp/page-header'; import { LeftContent } from './LeftContent'; import { RightContent } from './RightContent'; <PageHeader position="relative" leftContent={LeftContent} rightContent={RightContent} />;

Accessibility

  • The component renders a semantic <header> element. Ensure the page has a single main heading (e.g. the title in the left slot) for screen readers.
  • Provide an accessible label for icon-only buttons (e.g. title on MoreMenuMedium, or aria-label on IconButton).
  • When using tabs, pair TabLists and TabTrigger from @camp/tabs so keyboard and screen reader behavior is handled by the design system.
Last updated on