Large Title Header React component for Tailwind CSS v4
v1.1.0Updated in 1.11.0
A React iOS large title header that shrinks into a compact title in a glass bar as you scroll.
Scroll the page and the large title slides up with the content, fading as it passes under the bar; exactly when it disappears the compact title rises into the bar and the glass surface and hairline fade in, all following your finger. Let go halfway through the handover and it settles to fully expanded or fully collapsed. Pull past the top on a phone and the title stretches up to 8% from its corner. Tap the search field and the page scrolls so the field sits right under the bar, the Cancel button slides in from the end and the field makes room; type to filter, tap the clear button to empty it, tap Cancel (or press Escape) to clear, close the keyboard and return to the top. The back button (a link or a button, labelled with the previous page) and the trailing actions stay in the bar at 44px on touch. With the keyboard Tab goes back, actions, search, cancel; the title is the page's only <h1>, and when Escape or Cancel ends a search from the keyboard, focus returns to it instead of getting lost. Under reduced motion the handover is an instant switch and nothing stretches or slides.
Large Title Header is a Pro React component in the React mobile components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add large-title-header, together with UIProvider, Button, Input, Navigation, useScrollState and 3 more and the npm packages motion and lucide-react.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add large-title-headerLarge Title Header is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import LargeTitleHeader from @/components/ui/large-title-header.
"use client"
import { useState } from "react"
import { SquarePen } from "lucide-react"
import { Button } from "@/components/ui/button"
import { LargeTitleHeader } from "@/components/ui/large-title-header"
const conversations = [
{ id: "1", name: "Daniel Reed", message: "I sent proposal #Q-2026-118." },
{ id: "2", name: "Sophia Lee", message: "Invoice #2026-0412 was paid." },
]
export function MessagesPage() {
const [query, setQuery] = useState("")
const results = conversations.filter((c) => c.name.toLowerCase().includes(query.toLowerCase()))
return (
<>
<LargeTitleHeader
title="Messages"
subtitle="3 unread"
backLabel="Settings"
backHref="/settings"
search
searchValue={query}
onSearchChange={setQuery}
actions={
<Button variant="ghost" size="icon" radius="full" aria-label="New message">
<SquarePen />
</Button>
}
/>
<ul className="min-h-dvh">
{results.map((c) => (
<li key={c.id} className="px-4 py-3">
<p className="font-medium">{c.name}</p>
<p className="text-sm text-muted-foreground">{c.message}</p>
</li>
))}
</ul>
</>
)
}Props
titledefault""ReactNodeThe page title: large under the bar (the page's <h1>, see headingAs), compact in the bar once it scrolls away. Wraps to two lines when long; the compact copy truncates.
headingAsdefault"h1""h1" | "h2" | "h3" | "div"The title's element, for the large title and, in compact mode, the bar title. Keep h1 for the screen's own header; use h2, h3 or div inside a page that already has its h1.
subtitledefault""ReactNodeA muted line under the large title ("23 necitite").
compactTitleReactNodeA shorter title for the bar. Default: the title.
backLabeldefault""stringThe back button's text, usually the previous page ("Settings"). The button renders when backHref or onBack is set; without a label it is a chevron named by backAriaLabel.
backAriaLabeldefault"Back"stringThe back button's accessible name when it shows only the chevron.
backHrefdefault""stringMakes the back button a link through NavLink (the app's router link).
onBack() => voidRuns when the back button is pressed (with backHref, before the navigation).
actionsReactNodeTrailing buttons in the bar: <Button variant="ghost" size="icon" radius="full" aria-label="…" /> for icons, variant="ghost" size="sm" for text.
modedefault"collapse""collapse" | "large" | "compact"collapse: the large title scrolls away and hands over to the bar. large: the title stays pinned at full size and never collapses. compact: only the bar, with the title always in it (detail pages).
titleSizedefault"lg""md" | "lg"The large title at 28px (md) or 34px (lg, iOS).
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"The tint of the back and cancel buttons and the search field's focus ring and caret (iOS tints them). Neutral keeps the default ring.
colordefault""stringAny CSS color for the back and cancel buttons and the search focus ring and caret. Replaces the tone.
backgrounddefault"blur""blur" | "solid" | "transparent"The bar's surface once content is under it: frosted glass, the solid page color, or none. The bar is transparent over the large title in every mode. Set [--bar-bg:var(--surface)] when the page is not bg-background.
borderdefault"scrolled""scrolled" | "always" | "never"The hairline under the bar: fades in with the surface, always visible, or never.
searchdefaultfalsebooleanA search field under the title. Focusing it scrolls it right under the bar and shows Cancel; Escape or Cancel clears, blurs and scrolls back to the top. Keep the results at least a screen tall while searching (min-h-full) so the field can stay under the bar.
searchValuestringThe query, controlled. Cancel calls onSearchChange("").
defaultSearchValuedefault""stringThe first query while uncontrolled.
onSearchChange(value: string) => voidEvery change of the query, typing, clearing and Cancel.
onSearchingChange(searching: boolean) => voidTrue while the search is active (focused or holding a query), so the page can swap to results.
searchPlaceholderdefault"Search"stringThe field's placeholder and accessible name.
cancelLabeldefault"Cancel"stringThe text of the button that ends the search.
searchInputPropsPartial<InputProps>Anything else for the search Input: name, maxLength, loading, a ref, extra handlers.
stretchdefaulttruebooleanThe large title grows up to 8% from its top corner while you pull past the top (iOS overscroll, Safari only). Off under reduced motion.
snapdefaulttruebooleanA scroll that comes to rest halfway through the handover settles to fully expanded or fully collapsed, so the title never stays half under the bar (iOS). A page too short to collapse settles back to expanded.
safeAreadefaulttruebooleanPads env(safe-area-inset-top) above the bar so it clears the notch in a standalone PWA. It is 0 in desktop browsers.
scrollTargetHTMLElement | Window | RefObject<HTMLElement | null> | nullWhat scrolls. Default: the nearest ScrollContainerProvider, else the window.
linkComponent(props: LinkComponentProps) => ReactNodeThe router link for backHref on this header only. Usually set once for the app with LinkProvider.
classNamesPartial<Record<"bar" | "surface" | "hairline" | "row" | "leading" | "back" | "compactTitle" | "actions" | "large" | "title" | "subtitle" | "search" | "input" | "cancel", string>>Extra classes for the inner parts.
classNamestringExtra classes for the root. The root is display: contents (so the bar sticks to the whole page), except in mode="large" where it is the sticky block. The root carries data-collapsed and data-searching for group- styling.
Examples
Back navigation
A push from Settings to Notifications with a back button labelled with the previous page.
Large and compact
mode="large" never collapses; mode="compact" is only the bar.
With a tab bar
A searchable inbox between a large title and a bottom tab bar.
Medium, solid
titleSize="md" on a surface, with a solid bar and a permanent hairline.
Over a hero photo
White title over a photo; the bar turns to glass when it collapses.
Dependencies
Files
- components/ui/large-title-header.tsx
FAQ
Is the React Large Title Header component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Large Title Header?
Run npx wingo-ui@latest add large-title-header. It also adds the Wingo UI items it builds on (UIProvider, Button, Input, Navigation, useScrollState and 3 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/large-title-header.
How does Large Title Header behave on phones?
Pull past the top on a phone and the title stretches up to 8% from its corner.
See also
Used in
More React mobile components
Articles using this component
- Konsta UI Alternative for React: Ionic vs Wingo UI
Comparisons and alternatives10 min read
- React Collapsing Header: iOS Large Title and Photo Hero
Mobile UI in React8 min read
- Web App That Feels Native on a Phone: 12 React Fixes
Mobile UI in React11 min read