Page Header
The title, description, and main actions at the top of a page. Inside an app shell it moves its title and actions into the shared header bar.
Spring launch
Shared space for the launch team's chats, files, and instructions.
Usage
import { PageHeader } from "@tulipfarm/sprout/page-header";
<PageHeader
title="Files"
description="Find, open, and organize workspace files."
actions={<>
<Button><Upload aria-hidden="true" />Upload</Button>
<Button variant="outline"><FolderAdd aria-hidden="true" />New folder</Button>
</>}
/>title renders the page's only h1. The description sits under it. The actions sit at the end of the row and wrap under the title when space runs out. Long titles wrap; they never overflow.
Usage
Credits, and where they go. Split by model, agent, or activity.
Workflows
See how repeatable work runs. Create and edit workflows in chat.
Chats
Shared with everyone in Spring launch. Most recently active first.
Files
Find, open, and organize workspace files. Sharing a file never changes who owns it.
Agents
Private instructions you can share with people and teams.
Workflows
Calendar
Q3 customer retention analysis – board review copy (final).xlsx
2.4 MB · Owned by you
Import skill
New agent
Give it a role. Choose its access. Review before it starts.
Weekly pipeline digest
Start tasks with this agent. Managers set up how it runs and who can use it.
Spring launch
Back link and breadcrumb
<PageHeader
title="Customer accounts"
parent={{ label: "Tables", link: <Link to="/tables" /> }}
/>
<PageHeader
title="Import skill"
back={{ label: "Back to skills", link: <Link to="/skills" /> }}
/>back adds a small ghost link above the title. Below 640px only its chevron shows; the label stays its accessible name. A parent shows the title as the last step of a breadcrumb. Both take your router's link element, so links stay real links.
Moving focus to the title
Set focusable to let code focus the heading, for example after a route change or after an action removes the focused control. Use titleRef to reach it and titleId to label a region with it.
Skills
Reusable procedures. Skills never grant tools or permissions.
App header
const [title, setTitle] = useState<HTMLDivElement | null>(null);
const [actions, setActions] = useState<HTMLDivElement | null>(null);
const chrome = useMemo(
() => ({ title, actions, documentTitle: (page) => `${page} · Northwind` }),
[title, actions],
);
<header>
<SidebarTrigger />
<div ref={setTitle} className="flex min-w-0 flex-1 items-center gap-2" />
<div ref={setActions} className="flex shrink-0 items-center gap-2" />
</header>
<PageChromeContext value={chrome}>
<Outlet />
</PageChromeContext>When PageChromeContext has both elements, the back link and title move into the header bar at 14px and truncate on one line. Actions move beside them. The description stays in the page. Pages without a header use PageActions to place actions there, or right-aligned in the page when there is no header bar.
documentTitle is optional. When set, a string title also updates the browser tab and restores it when the page leaves.
Accessibility
The title is an h1. The breadcrumb is a nav named “Breadcrumb”, its last step marked aria-current="page", and its chevrons are hidden from assistive technology. A focusable title shows a focus ring only for keyboard focus. Link colors change over 120ms; reduced motion turns this off. Routing, dialogs, and menus in these examples are sample code.