Condensing header
FreeA page header that makes room as you read: the title shrinks into a bar, the description folds away and a border appears, following the scroll.
pnpm dlx shadcn@latest add https://caliperui.site/r/condensing-header.jsonInvoices
128 this year · €412,300 billed · 6 overdue
- INV-2041€1,240
- INV-2040€1,555
- INV-2039€1,870
- INV-2038€2,185
- INV-2037€2,500
- INV-2036€2,815
- INV-2035€3,130
- INV-2034€3,445
- INV-2033€3,760
- INV-2032€4,075
- INV-2031€4,390
- INV-2030€4,705
- INV-2029€5,020
- INV-2028€5,335
- INV-2027€5,650
- INV-2026€5,965
- INV-2025€6,280
- INV-2024€6,595
When to use #
Use it for
- Long settings, record and list pages.
- Phone screens where vertical space is short.
Skip it when
- Short pages that never scroll.
Installation #
terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/condensing-header.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
example.tsx
import { Plus } from "lucide-react" import { useRef } from "react" import { Button } from "@/components/ui/button" import { CondensingHeader } from "@/components/ui/condensing-header" export function CondensingHeaderDemo() { const scroller = useRef<HTMLDivElement>(null); return ( <div ref={scroller} className="h-[420px] w-full max-w-md overflow-y-auto rounded-[14px] shadow-[inset_0_0_0_1px_var(--border)]" tabIndex={0} role="region" aria-label="Invoices page"> <CondensingHeader scrollRoot={scroller} title="Invoices" description="128 this year · €412,300 billed · 6 overdue" actions={<Button size="sm"><Plus aria-hidden="true" />New</Button>} /> <ul className="grid px-5 pb-6"> {Array.from({ length: 18 }, (_, index) => ( <li key={index} className="flex justify-between border-b border-border py-3 text-sm last:border-0"> <span>INV-{2041 - index}</span> <span className="font-mono text-muted-foreground">€{(1240 + index * 315).toLocaleString("en-GB")}</span> </li> ))} </ul> </div> ); } const actions = ["approved INV-2041", "commented on the Ostra deal", "matched 12 payments", "invited a teammate", "closed September", "exported the ledger", "changed a rule"];
API reference #
CondensingHeader
component
PropTypeDefaultDescription
title *string—
descriptionReactNode—
actionsReactNode—
distancenumber72Pixels of scroll over which it condenses.
scrollRootRefObject<HTMLElement | null>—The element that scrolls, if not the window.
classNamestring—
Accessibility #
It is built on native elements, so roles and focus come from the browser.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It checks prefers-reduced-motion itself and settles immediately instead of travelling. Every state is still reachable.