Page Header
The first line of every admin screen — title, a scope line the host can rewrite in place, an optional count badge, and a wrapping action cluster.
Preview
Customers
Everyone who has ordered from, registered with, or been added to this store.
<div class="w-full">
<x-ui.admin.page-header />
</div>
Installation
php artisan ui:add admin-page-header
Registry contract
php artisan ui:add admin-page-header
writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.
-
resources/views/components/ui/admin/page-header.blade.php
Use with AI
A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.
# Brok UI: Page Header (`admin-page-header`)
The first line of every admin screen — title, a scope line the host can rewrite in place, an optional count badge, and a wrapping action cluster.
Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.
## Install
```bash
php artisan ui:add admin-page-header
```
## Usage
```blade
<div class="w-full">
<x-ui.admin.page-header />
</div>
```
## Props
- `title` (string, default `Customers`) — The page title.
- `scope` (string|false|null, default `null`) — A sentence describing what the page covers. `null` renders a sample sentence for the preview; `false` renders none.
- `count` (int|string|null, default `null`) — A count badge beside the title.
- `countLabel` (string|null, default `null`) — Badge text when `count` is set; defaults to the bare count.
- `eyebrow` (string|null, default `null`) — A small uppercase line above the title (a module or section name).
- `as` ('h1'|'h2', default `h1`) — Heading level of the title.
## Use when
- Use to structure hierarchy, spacing, and responsiveness so content is easier to scan and navigate.
- Every admin list, record and form page: it fixes where the title, the scope sentence and the page-level actions sit.
- A list that refreshes in place must update its scope sentence — target `[data-slot="page-header-scope"]`.
## Avoid when
- Do not let layout primitives substitute for semantics, headings, or interaction rules users still need.
- A marketing section heading — use `section-heading`.
- A record edit screen whose header must stay sticky with save state — use `admin-record-header`.
## Anti-patterns
- Using visual layout as a substitute for semantic structure
## Rules
- Use the `<brok:admin-page-header>` tag (or `<x-ui.admin-page-header>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.
## Links
- Docs: https://brokui.dev/docs/components/admin-page-header
- Registry JSON (files, props, contract): https://brokui.dev/r/open/admin-page-header.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | Customers | The page title. |
| scope | string | false | null | null | A sentence describing what the page covers. `null` renders a sample sentence for the preview; `false` renders none. |
| count | int | string | null | null | A count badge beside the title. |
| countLabel | string | null | null | Badge text when `count` is set; defaults to the bare count. |
| eyebrow | string | null | null | A small uppercase line above the title (a module or section name). |
| as | 'h1' | 'h2' | h1 | Heading level of the title. |
Slots
actions— The page-level action cluster (create, import, shortcut chips). A sample Import/New pair renders when omitted.
Renders as h1, h2.
Data slots
Stable hooks for CSS overrides and browser tests.
Behavior
- The actions cluster is `min-w-0 flex-wrap`, so it wraps under the title on a narrow screen instead of pushing it sideways.
- The scope line carries a stable `data-slot` so a host can rewrite the count without re-rendering the header.
- Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.
Guidance
Structure content hierarchy and responsive relationships.
Use when
- Use to structure hierarchy, spacing, and responsiveness so content is easier to scan and navigate.
- Every admin list, record and form page: it fixes where the title, the scope sentence and the page-level actions sit.
- A list that refreshes in place must update its scope sentence — target `[data-slot="page-header-scope"]`.
Avoid when
- Do not let layout primitives substitute for semantics, headings, or interaction rules users still need.
- A marketing section heading — use `section-heading`.
- A record edit screen whose header must stay sticky with save state — use `admin-record-header`.
Use instead
- Semantic HTML with standard flow
Anti-patterns
- Using visual layout as a substitute for semantic structure
- Anatomy
- Theming hooks
Accessibility
- Keyboard
- No component-owned keyboard interaction; native element behavior applies.
- Focus
none
- Exactly one page title element; the count badge is text, never colour alone.
- Semantic HTML and a stable
data-slotattribute for styling and scripting hooks. - Focus-visible rings use the
ringtoken, so keyboard focus is always visible. - Disabled and invalid states are conveyed to assistive tech, not by color alone.
- Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
- Labels go through
__()and layout uses logical properties (ms-*,text-start), so it mirrors underdir="rtl"— flip the preview to RTL to confirm. - Dark mode uses the same semantic tokens under the
darkclass; high contrast follows forced-color system tokens.
Livewire
Livewire can update this component through forwarded wire:* attributes.
Source
The exact, editable file ui:add writes
into your app. Previews render this same code; there are no preview-only components.
{{--
Page Header — the first line of every admin screen: what this page is,
how much of it there is, and the actions that apply to the whole page.
The scope line carries a stable `data-slot` on purpose. A list that
refreshes in place (server-mode filtering, a saved view applied from a
KPI tile) must rewrite "34 orders" to "6 orders" without re-rendering the
header; the host targets `[data-slot="page-header-scope"]` and sets its
text. Printing the count once and leaving it stale over a filtered list
is the bug this component exists to prevent.
The action cluster is a slot, not a prop array: the actions on a page
header are the page's own (create, import, a legacy-screen link, a
shortcut chip into a saved view) and each one carries its own wiring.
The component only decides where they sit and how they wrap.
Generalised from the Noord-C admin's `v2/page-header.blade.php`, which
every one of its forty rebuilt screens opened with.
--}}
@props([
'title' => 'Customers',
'scope' => null,
'count' => null,
'countLabel' => null,
'eyebrow' => null,
'as' => 'h1',
])
@php
// Shapes documented in item.json knowledge.props:
// scope: a sentence describing what the page covers ("34 customers in this store"), rewritten in place by the host on refresh.
// count/countLabel: a badge beside the title ("128" / "128 records") when the scope line is not wanted.
$tag = in_array($as, ['h1', 'h2'], true) ? $as : 'h1';
// `null` (absent) renders a sample scope line so the docs preview reads
// as a real header; pass `:scope="false"` for a header with no scope line.
$scope ??= $count === null
? __('Everyone who has ordered from, registered with, or been added to this store.')
: false;
@endphp
<header
data-slot="page-header"
data-surface="admin"
{{ $attributes->merge(['class' => 'flex min-w-0 flex-wrap items-start justify-between gap-4']) }}
>
<div class="min-w-0 flex-1 basis-64">
@if ($eyebrow !== null)
<p data-slot="page-header-eyebrow" class="text-xs font-medium tracking-wide text-muted-foreground uppercase">{{ $eyebrow }}</p>
@endif
<div class="flex min-w-0 flex-wrap items-center gap-2">
<{{ $tag }} data-slot="page-header-title" class="min-w-0 truncate text-xl font-semibold tracking-tight">{{ $title }}</{{ $tag }}>
@if ($count !== null)
<x-ui.badge variant="secondary" data-slot="page-header-count">
{{ $countLabel ?? $count }}
</x-ui.badge>
@endif
</div>
@if ($scope)
<p data-slot="page-header-scope" class="mt-2 max-w-2xl text-sm text-pretty text-muted-foreground">{{ $scope }}</p>
@endif
</div>
@isset($actions)
<div data-slot="page-header-actions" class="flex min-w-0 flex-wrap items-center gap-2">
{{ $actions }}
</div>
@else
<div data-slot="page-header-actions" class="flex min-w-0 flex-wrap items-center gap-2">
<x-ui.button variant="outline" size="sm" href="#">{{ __('Import') }}</x-ui.button>
<x-ui.button size="sm" href="#">{{ __('New customer') }}</x-ui.button>
</div>
@endisset
</header>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.2 - Status
- Stable
- License
-
open - Accessibility reviewed
- No review date recorded
- Last breaking change
- No date recorded
- Deprecation
- Not deprecated
- Contract
-
v6 - Foundation
-
≥ 1.0.0