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
Install
yarn add @camp/page-headerUsage
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 (
Textash1), tabs (TabLists/TabTrigger), or breadcrumbs (Breadcrumbs) with optional actions (e.g.IconButton). - Right: Primary/secondary actions (
Button), status text, or an overflow menu (IconButtonwith 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
Textash1). - 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.
IconButtonwithMoreMenuMedium) instead of multiple buttons. - Use
PageHeaderPipeSeparatorfrom@camp/page-headerbetween 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.
titleonMoreMenuMedium, oraria-labelonIconButton). - When using tabs, pair
TabListsandTabTriggerfrom@camp/tabsso keyboard and screen reader behavior is handled by the design system.