Pattern gallery

Page title variants

One fixed hierarchy, identity then title then actions, so a reader parses any page the same way.

What this solves

Gestalt hierarchy and self-explaining action container. Every page opens with the same fixed order, identity, title, subtitle, then actions, so a reader parses a brand-new page the same way they parsed the last one, and the actions bar states up front what this page lets them do.
Use it when
  • A list page's header, with an icon, a subtitle, and a primary action.Speedway's Jobs page (jobs.tsx:186-195): a plain icon plus a New job button.
  • A module or workspace whose identity carries a theme color.Speedway's Modules page (modules.tsx:680-688): the module's own accent rides the avatar slot.
  • A status that doubles as a live filter toggle riding beside the title.Walmart's Jobs page (Jobs.tsx:833-852): the in-review StatusPill both reports and filters.

Rendered

Fixture data; check both themes.
Plain icon + toolbar

Jobs

Each time you run a module, it shows up here.
Themed identity chip

Workflow

Chain modules into one run.
Status pill beside the title

Jobs

in review3
Runs across every module.
Loading skeleton

Jobs

Each time you run a module, it shows up here.
Back-linked detail header

Run 4

Brake pads Q3 · started 9m ago
patterns/page-title-variants/example.tsxCopy this into a fresh route and it renders as above.
"use client";
import { useState } from "react";
import { Button, PageTitle, RenderIcon, StatusPill } from "@versable-git/ui";
// Five shipping shapes of one header row. The identity disc and the loading
// state are the variant axes: a plain Icon, a theme-colored chip riding the
// avatar slot (a custom title span would skip the kit's h1 styling and drift
// off the house size, so the tile rides the identity slot instead), the
// skeleton mirroring whichever slots the loaded row will use, and a
// back-linked detail header.
export function PageTitleVariants() {
const [loaded, setLoaded] = useState(true);
return (
<div className="flex flex-col gap-8">
<div className="flex flex-col gap-2">
<span className="text-base-content/45 text-xs font-medium tracking-wide uppercase">Plain icon + toolbar</span>
<PageTitle
Icon="Table"
title="Jobs"
subtitle="Each time you run a module, it shows up here."
actions={<Button color="primary" size="sm" Icon="Success" content="New job" />}
/>
</div>
<div className="flex flex-col gap-2">
<span className="text-base-content/45 text-xs font-medium tracking-wide uppercase">Themed identity chip</span>
<PageTitle
avatar={<RenderIcon Icon="Refresh" size={18} />}
iconWrapClassName="bg-success/10 text-success rounded-lg"
title="Workflow"
subtitle="Chain modules into one run."
/>
</div>
<div className="flex flex-col gap-2">
<span className="text-base-content/45 text-xs font-medium tracking-wide uppercase">Status pill beside the title</span>
<PageTitle
Icon="Table"
title="Jobs"
subtitle="Runs across every module."
titleExtra={
<StatusPill kind="review" size="sm" count={3}>
in review
</StatusPill>
}
/>
</div>
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<span className="text-base-content/45 text-xs font-medium tracking-wide uppercase">Loading skeleton</span>
<Button
size="xs"
variant="outline"
content={loaded ? "Reload" : "Loaded"}
onClick={() => setLoaded((v) => !v)}
/>
</div>
<PageTitle
skeleton={!loaded}
Icon="Table"
title="Jobs"
subtitle="Each time you run a module, it shows up here."
actions={<Button color="primary" size="sm" Icon="Success" content="New job" />}
/>
</div>
<div className="flex flex-col gap-2">
<span className="text-base-content/45 text-xs font-medium tracking-wide uppercase">Back-linked detail header</span>
<PageTitle
Icon="Refresh"
back={
<a href="#jobs" onClick={(e) => e.preventDefault()}>
Back to Jobs
</a>
}
title="Run 4"
subtitle="Brake pads Q3 · started 9m ago"
actions={<Button variant="outline" size="sm" content="View log" />}
/>
</div>
</div>
);
}

Where it ships

  • speedway/app/routes/workspaces/jobs/jobs.tsx:186-195plain Icon plus an actions toolbar
  • speedway/app/routes/workspaces/modules.tsx:680-688the themed chip rides the avatar slot; each module gets its identity color from shared meta
  • walmart-mvp/frontend/src/pages/Jobs.tsx:833-852titleExtra carries a live StatusPill that doubles as a review filter toggle

App-specific: Identity colors come from the apps' module meta maps, the pill in variant three toggles a real filter, and back-links ride the back slot. The apps never restyle the title span itself; anything custom rides avatar, titleExtra, or actions.

@versable-git/ui · composites proven in the apps