# Page header

The top of every page that isn't a thread: where you are (breadcrumb), what the page is, what you can do here (actions), and its views (tabs). Tabs are a nav of views over the same page, marked with aria-current; counts appear only when the service gave one.

- Registry name: `page-header` (`@candor/page-header`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/page-header

## Install

```bash
npx candor-ui add page-header
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/page-header`.
It brings in: locale, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import * as React from "react"
import { Plus } from "lucide-react"
import { PageHeader, type PageTab } from "@/components/page-header"
import { Button } from "@/components/ui/button"

const tabs: PageTab[] = [
  { id: "open", label: "Open", count: 3 },
  { id: "applied", label: "Applied", count: 18 },
  { id: "rolled-back", label: "Rolled back" },
]

export default function Example() {
  const [tab, setTab] = React.useState("open")
  return (
    <div className="max-w-2xl overflow-hidden rounded-lg border">
      <PageHeader
        breadcrumb={[{ label: "Acme", onClick: () => {} }, { label: "Storefront", onClick: () => {} }]}
        title="Migrations"
        description="Schema changes the agents have proposed or applied."
        actions={
          <Button size="sm">
            <Plus /> New migration
          </Button>
        }
        tabs={tabs}
        activeTab={tab}
        onTabChange={setTab}
      />
    </div>
  )
}
```

## <PageHeader>

Props:

- `title: string`: What the page is, as its heading.
- `description?: React.ReactNode | undefined`: A line under the title saying what the page is for.
- `breadcrumb?: Crumb[] | undefined`: Where the page sits, from the top; a crumb with onClick is a link back.
- `actions?: React.ReactNode | undefined`: Buttons for what you can do here, right of the title.
- `tabs?: PageTab[] | undefined`: Views of the page, shown under the title; a count shows only when given.
- `activeTab?: string | undefined`: The id of the current view, marked with aria-current.
- `onTabChange?: ((id: string) => void) | undefined`: Called with a view's id when its tab is chosen.
- `className?: string | undefined`

## Strings (`pageHeader`)

The fixed words, English by default. Override any of them under `pageHeader` in `<LocaleProvider strings={{ pageHeader: { … } }}>`; the table is exported as `pageHeaderStrings`.

- `breadcrumb`: Breadcrumb
- `views`: {title} views

## Types

### Crumb

```ts
{ label: string; onClick?: (() => void) | undefined }
```

### PageTab

```ts
{ id: string; label: string; count?: number | undefined }
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
