Skip to main content
Nexus Design System
GitHub

PageHeader

PageHeader titles a page or section, with optional metadata, status, description and actions. Compact, standard and detail headers are compositions of the same parts, not variants.

  • The title renders an h1. Use asChild to pick another heading level.
  • For a larger title, add className="nx:typography-heading-large" to PageHeaderTitle.
  • Put page headers inside main and section headers inside their section.
  • Actions wrap below the content in narrow containers. Your app owns what they do.

Activity report

Review activity for the selected period.

'use client';

import type { ReactNode } from 'react';

import { Button } from '@/components/nxds/components/button/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/nxds/components/page-header/page-header';

function ReportHeader({
  title = <PageHeaderTitle>Activity report</PageHeaderTitle>,
}: {
  title?: ReactNode;
}) {
  return (
    <PageHeader>
      <PageHeaderContent>
        {title}
        <PageHeaderDescription>
          Review activity for the selected period.
        </PageHeaderDescription>
      </PageHeaderContent>
      <PageHeaderActions>
        <Button variant="outline">Export</Button>
        <Button>Share</Button>
      </PageHeaderActions>
    </PageHeader>
  );
}

export default function PageHeaderDefault() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <ReportHeader />
    </main>
  );
}

This example also needs: Button.

Installation

npx nxds-cli@latest add page-header

Run npx nxds-cli@latest init first if nxds isn’t set up in your app yet. See Install.

Usage

import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderMeta,
  PageHeaderTitle,
  PageHeaderTitleRow,
} from '@/components/nxds/components/page-header/page-header';

Composition

PageHeaderTitle
PageHeader
├── PageHeaderContent
│   ├── PageHeaderDescription
│   ├── PageHeaderTitle
│   ├── PageHeaderMeta
│   └── PageHeaderTitleRow
└── PageHeaderActions

Examples

Section header

Title a section inside a page with an h2 through asChild.

Notification settings

Choose which updates you receive.

'use client';

import { useId } from 'react';

import { Button } from '@/components/nxds/components/button/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/nxds/components/page-header/page-header';

function NotificationSettingsSection() {
  const titleId = useId();

  return (
    <section aria-labelledby={titleId}>
      <PageHeader>
        <PageHeaderContent>
          <PageHeaderTitle asChild>
            <h2 id={titleId}>Notification settings</h2>
          </PageHeaderTitle>
          <PageHeaderDescription>
            Choose which updates you receive.
          </PageHeaderDescription>
        </PageHeaderContent>
        <PageHeaderActions>
          <Button variant="outline">Reset</Button>
        </PageHeaderActions>
      </PageHeader>
    </section>
  );
}

export default function PageHeaderSectionHeader() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <NotificationSettingsSection />
    </main>
  );
}

Compact

Pair a title with one small action for a dense page.

Reports

'use client';

import type { ReactNode } from 'react';

import { Button } from '@/components/nxds/components/button/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderTitle,
} from '@/components/nxds/components/page-header/page-header';

function CompactHeader({
  title = (
    <PageHeaderTitle className="nx:typography-heading-small">
      Reports
    </PageHeaderTitle>
  ),
}: {
  title?: ReactNode;
}) {
  return (
    <PageHeader>
      <PageHeaderContent>{title}</PageHeaderContent>
      <PageHeaderActions>
        <Button size="sm">New report</Button>
      </PageHeaderActions>
    </PageHeader>
  );
}

export default function PageHeaderCompact() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <CompactHeader />
    </main>
  );
}

Detail

Show a record with metadata, a status Badge in PageHeaderTitleRow and actions.

PO-0001 · Project 254

Purchase order

Sent

Office furniture for the Riverside workspace.

Supplier
Riverside Furniture
Delivery date
'use client';

import type { ReactNode } from 'react';

import { Badge } from '@/components/nxds/components/badge/badge';
import { Button } from '@/components/nxds/components/button/button';
import {
  DescriptionList,
  DescriptionListDescription,
  DescriptionListItem,
  DescriptionListTerm,
} from '@/components/nxds/components/description-list/description-list';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderMeta,
  PageHeaderTitle,
  PageHeaderTitleRow,
} from '@/components/nxds/components/page-header/page-header';

function DetailHeader({
  title = <PageHeaderTitle>Purchase order</PageHeaderTitle>,
}: {
  title?: ReactNode;
}) {
  return (
    <div className="nx:grid nx:gap-6">
      <PageHeader>
        <PageHeaderContent>
          <PageHeaderMeta>PO-0001 · Project 254</PageHeaderMeta>
          <PageHeaderTitleRow>
            {title}
            <Badge variant="secondary">Sent</Badge>
          </PageHeaderTitleRow>
          <PageHeaderDescription>
            Office furniture for the Riverside workspace.
          </PageHeaderDescription>
        </PageHeaderContent>
        <PageHeaderActions>
          <Button variant="outline">Download</Button>
          <Button>Edit order</Button>
        </PageHeaderActions>
      </PageHeader>
      <DescriptionList>
        <DescriptionListItem>
          <DescriptionListTerm>Supplier</DescriptionListTerm>
          <DescriptionListDescription>
            Riverside Furniture
          </DescriptionListDescription>
        </DescriptionListItem>
        <DescriptionListItem>
          <DescriptionListTerm>Delivery date</DescriptionListTerm>
          <DescriptionListDescription>
            <time dateTime="2026-10-12">12 October 2026</time>
          </DescriptionListDescription>
        </DescriptionListItem>
      </DescriptionList>
    </div>
  );
}

export default function PageHeaderDetail() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <DetailHeader />
    </main>
  );
}

This example also needs: Badge, DescriptionList.

With tabs

Place Tabs under the header to switch between views of the page.

Usage

Monitor activity and spending across your workspace.

Activity for the current billing period.

'use client';

import type { ReactNode } from 'react';

import {
  PageHeader,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/nxds/components/page-header/page-header';
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from '@/components/nxds/components/tabs/tabs';

function TabbedHeader({
  title = <PageHeaderTitle>Usage</PageHeaderTitle>,
}: {
  title?: ReactNode;
}) {
  return (
    <div className="nx:grid nx:gap-4">
      <PageHeader>
        <PageHeaderContent>
          {title}
          <PageHeaderDescription>
            Monitor activity and spending across your workspace.
          </PageHeaderDescription>
        </PageHeaderContent>
      </PageHeader>
      <Tabs defaultValue="activity">
        <TabsList aria-label="Usage views">
          <TabsTrigger value="activity">Activity</TabsTrigger>
          <TabsTrigger value="spend">Spend</TabsTrigger>
        </TabsList>
        <TabsContent value="activity">
          <p className="nx:typography-body-default nx:text-muted-foreground">
            Activity for the current billing period.
          </p>
        </TabsContent>
        <TabsContent value="spend">
          <p className="nx:typography-body-default nx:text-muted-foreground">
            Spending for the current billing period.
          </p>
        </TabsContent>
      </Tabs>
    </div>
  );
}

export default function PageHeaderWithTabs() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <TabbedHeader />
    </main>
  );
}

This example also needs: Tabs.

Large heading

Add nx:typography-heading-large to the title for a larger heading.

Workspace overview

Track usage, members, and billing across your workspace.

'use client';

import {
  PageHeader,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/nxds/components/page-header/page-header';

export default function PageHeaderLargeHeading() {
  return (
    <main className="nx:w-full nx:max-w-5xl nx:p-4">
      <PageHeader>
        <PageHeaderContent>
          <PageHeaderTitle className="nx:typography-heading-large">
            Workspace overview
          </PageHeaderTitle>
          <PageHeaderDescription>
            Track usage, members, and billing across your workspace.
          </PageHeaderDescription>
        </PageHeaderContent>
      </PageHeader>
    </main>
  );
}

Props

PageHeader

PageHeader adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderActions

PageHeaderActions adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderContent

PageHeaderContent adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderDescription

PageHeaderDescription adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderMeta

PageHeaderMeta adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderTitle

PageHeaderTitle props
PropTypeDefaultDescription
asChildbooleanfalse

Renders the child element with the title styles. Use it to change the heading level.

PageHeaderTitleRow

PageHeaderTitleRow adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeader titles a page or section, with optional metadata, status, description and actions. Compact, standard and detail headers are compositions of the same parts, not variants.

  • The title renders an h1. Use as-child to pick another heading level.
  • For a larger title, add class="nx:typography-heading-large" to PageHeaderTitle.
  • Put page headers inside main and section headers inside their section.
  • Actions wrap below the content in narrow containers. Your app owns what they do.
<script setup lang="ts">
import { Button } from '@/components/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/page-header';
</script>

<template>
  <PageHeader>
    <PageHeaderContent>
      <PageHeaderTitle>Activity report</PageHeaderTitle>
      <PageHeaderDescription
        >Review activity for the selected period.</PageHeaderDescription
      >
    </PageHeaderContent>
    <PageHeaderActions>
      <Button variant="outline">Export</Button>
      <Button>Share</Button>
    </PageHeaderActions>
  </PageHeader>
</template>

This example also needs: Button.

Installation

  1. Install the following dependencies:

    npm install reka-ui@^2.11.0
    
  2. Copy and paste the following code into your project.

    components/page-header/PageHeader.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderProps>();
    </script>
    
    <template>
      <header
        data-slot="page-header"
        :class="
          cn('nx:flex nx:w-full nx:flex-wrap nx:items-start nx:gap-4', props.class)
        "
      >
        <slot />
      </header>
    </template>
    
    components/page-header/PageHeaderActions.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderActionsProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderActionsProps>();
    </script>
    
    <template>
      <div
        data-slot="page-header-actions"
        :class="
          cn(
            'nx:flex nx:min-w-0 nx:max-w-full nx:flex-wrap nx:items-center nx:gap-2',
            props.class
          )
        "
      >
        <slot />
      </div>
    </template>
    
    components/page-header/PageHeaderContent.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderContentProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderContentProps>();
    </script>
    
    <template>
      <div
        data-slot="page-header-content"
        :class="
          cn(
            'nx:flex nx:min-w-0 nx:grow nx:basis-xs nx:flex-col nx:gap-1',
            props.class
          )
        "
      >
        <slot />
      </div>
    </template>
    
    components/page-header/PageHeaderDescription.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderDescriptionProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderDescriptionProps>();
    </script>
    
    <template>
      <p
        data-slot="page-header-description"
        :class="
          cn(
            'nx:m-0 nx:wrap-anywhere nx:typography-body-default nx:text-muted-foreground',
            props.class
          )
        "
      >
        <slot />
      </p>
    </template>
    
    components/page-header/PageHeaderMeta.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderMetaProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderMetaProps>();
    </script>
    
    <template>
      <p
        data-slot="page-header-meta"
        :class="
          cn(
            'nx:m-0 nx:wrap-anywhere nx:typography-label-small nx:text-muted-foreground',
            props.class
          )
        "
      >
        <slot />
      </p>
    </template>
    
    components/page-header/PageHeaderTitle.vue
    <script setup lang="ts">
    import { Primitive, type PrimitiveProps } from 'reka-ui';
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderTitleProps extends PrimitiveProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = withDefaults(defineProps<PageHeaderTitleProps>(), { as: 'h1' });
    </script>
    
    <template>
      <Primitive
        data-slot="page-header-title"
        :as="as"
        :as-child="asChild"
        :class="
          cn(
            'nx:m-0 nx:wrap-anywhere nx:typography-heading-medium nx:text-foreground',
            props.class
          )
        "
      >
        <slot />
      </Primitive>
    </template>
    
    components/page-header/PageHeaderTitleRow.vue
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue';
    
    import { cn } from '../../lib/utils';
    
    export interface PageHeaderTitleRowProps {
      class?: HTMLAttributes['class'];
    }
    
    const props = defineProps<PageHeaderTitleRowProps>();
    </script>
    
    <template>
      <div
        data-slot="page-header-title-row"
        :class="cn('nx:flex nx:flex-wrap nx:items-center nx:gap-2', props.class)"
      >
        <slot />
      </div>
    </template>
    
    components/page-header/index.ts
    export { default as PageHeader, type PageHeaderProps } from './PageHeader.vue';
    export {
      default as PageHeaderActions,
      type PageHeaderActionsProps,
    } from './PageHeaderActions.vue';
    export {
      default as PageHeaderContent,
      type PageHeaderContentProps,
    } from './PageHeaderContent.vue';
    export {
      default as PageHeaderDescription,
      type PageHeaderDescriptionProps,
    } from './PageHeaderDescription.vue';
    export {
      default as PageHeaderMeta,
      type PageHeaderMetaProps,
    } from './PageHeaderMeta.vue';
    export {
      default as PageHeaderTitle,
      type PageHeaderTitleProps,
    } from './PageHeaderTitle.vue';
    export {
      default as PageHeaderTitleRow,
      type PageHeaderTitleRowProps,
    } from './PageHeaderTitleRow.vue';
    
  3. Keep each file at the path shown above it.

    Paths are relative to packages/vue/src/. Keep the same folders under your @/ root, and the imports between files work without edits.

Usage

import { PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderMeta, PageHeaderTitle, PageHeaderTitleRow } from '@/components/page-header';

Examples

Section header

Title a section inside a page with an h2 through as-child.

<script setup lang="ts">
import { useId } from 'vue';

import { Button } from '@/components/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/page-header';

const titleId = useId();
</script>

<template>
  <section :aria-labelledby="titleId">
    <PageHeader>
      <PageHeaderContent>
        <PageHeaderTitle as-child>
          <h2 :id="titleId">Notification settings</h2>
        </PageHeaderTitle>
        <PageHeaderDescription
          >Choose which updates you receive.</PageHeaderDescription
        >
      </PageHeaderContent>
      <PageHeaderActions>
        <Button variant="outline">Reset</Button>
      </PageHeaderActions>
    </PageHeader>
  </section>
</template>

Compact

Pair a title with one small action for a dense page.

<script setup lang="ts">
import { Button } from '@/components/button';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderTitle,
} from '@/components/page-header';
</script>

<template>
  <PageHeader>
    <PageHeaderContent>
      <PageHeaderTitle class="nx:typography-heading-small"
        >Reports</PageHeaderTitle
      >
    </PageHeaderContent>
    <PageHeaderActions>
      <Button size="sm">New report</Button>
    </PageHeaderActions>
  </PageHeader>
</template>

Detail

Show a record with metadata, a status Badge in PageHeaderTitleRow and actions.

<script setup lang="ts">
import { Badge } from '@/components/badge';
import { Button } from '@/components/button';
import {
  DescriptionList,
  DescriptionListDescription,
  DescriptionListItem,
  DescriptionListTerm,
} from '@/components/description-list';
import {
  PageHeader,
  PageHeaderActions,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderMeta,
  PageHeaderTitle,
  PageHeaderTitleRow,
} from '@/components/page-header';
</script>

<template>
  <div class="nx:grid nx:gap-6">
    <PageHeader>
      <PageHeaderContent>
        <PageHeaderMeta>PO-0001 · Project 254</PageHeaderMeta>
        <PageHeaderTitleRow>
          <PageHeaderTitle>Purchase order</PageHeaderTitle>
          <Badge variant="secondary">Sent</Badge>
        </PageHeaderTitleRow>
        <PageHeaderDescription
          >Office furniture for the Riverside workspace.</PageHeaderDescription
        >
      </PageHeaderContent>
      <PageHeaderActions>
        <Button variant="outline">Download</Button>
        <Button>Edit order</Button>
      </PageHeaderActions>
    </PageHeader>
    <DescriptionList>
      <DescriptionListItem>
        <DescriptionListTerm>Supplier</DescriptionListTerm>
        <DescriptionListDescription
          >Riverside Furniture</DescriptionListDescription
        >
      </DescriptionListItem>
      <DescriptionListItem>
        <DescriptionListTerm>Delivery date</DescriptionListTerm>
        <DescriptionListDescription>
          <time datetime="2026-10-12">12 October 2026</time>
        </DescriptionListDescription>
      </DescriptionListItem>
    </DescriptionList>
  </div>
</template>

This example also needs: Badge, DescriptionList.

With tabs

Place Tabs under the header to switch between views of the page.

<script setup lang="ts">
import {
  PageHeader,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/page-header';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/tabs';
</script>

<template>
  <div class="nx:grid nx:gap-4">
    <PageHeader>
      <PageHeaderContent>
        <PageHeaderTitle>Usage</PageHeaderTitle>
        <PageHeaderDescription
          >Monitor activity and spending across your
          workspace.</PageHeaderDescription
        >
      </PageHeaderContent>
    </PageHeader>
    <Tabs default-value="activity">
      <TabsList aria-label="Usage views">
        <TabsTrigger value="activity">Activity</TabsTrigger>
        <TabsTrigger value="spend">Spend</TabsTrigger>
      </TabsList>
      <TabsContent value="activity">
        <p class="nx:typography-body-default nx:text-muted-foreground">
          Activity for the current billing period.
        </p>
      </TabsContent>
      <TabsContent value="spend">
        <p class="nx:typography-body-default nx:text-muted-foreground">
          Spending for the current billing period.
        </p>
      </TabsContent>
    </Tabs>
  </div>
</template>

This example also needs: Tabs.

Large heading

Add nx:typography-heading-large to the title for a larger heading.

<script setup lang="ts">
import {
  PageHeader,
  PageHeaderContent,
  PageHeaderDescription,
  PageHeaderTitle,
} from '@/components/page-header';
</script>

<template>
  <PageHeader>
    <PageHeaderContent>
      <PageHeaderTitle class="nx:typography-heading-large"
        >Workspace overview</PageHeaderTitle
      >
      <PageHeaderDescription
        >Track usage, members, and billing across your
        workspace.</PageHeaderDescription
      >
    </PageHeaderContent>
  </PageHeader>
</template>

Props

PageHeader

PageHeader adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderActions

PageHeaderActions adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderContent

PageHeaderContent adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderDescription

PageHeaderDescription adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderMeta

PageHeaderMeta adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderTitle

PageHeaderTitle adds no props of its own; it accepts the props of the element or primitive it wraps.

PageHeaderTitleRow

PageHeaderTitleRow adds no props of its own; it accepts the props of the element or primitive it wraps.