Page title variants
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 + toolbarEach time you run a module, it shows up here.
Jobs
Themed identity chipChain modules into one run.
Workflow
Status pill beside the titleRuns across every module.
Jobs
in review3Loading skeleton
Jobs
Back-linked detail header
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 toolbarspeedway/app/routes/workspaces/modules.tsx:680-688the themed chip rides the avatar slot; each module gets its identity color from shared metawalmart-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.