Page Header Variants: 8 Designs for App and Marketing Pages
8 practical page header variants for React apps — sticky, glassmorphic, hero, split, minimal, and more. Built with Tailwind v4 and copy-paste ready.
Why Your Page Header Is Doing More Work Than You Think
Honestly, most developers treat the page header as an afterthought — slap in a logo, a nav list, maybe a button, and call it done. That's a mistake. The header is literally the first rendered thing above the fold. It sets the visual register for everything else on the page.
App headers and marketing headers have wildly different jobs. An app header needs to stay out of the way — users are there to work, not admire your design. A marketing header needs to carry brand weight, guide attention, and push toward a CTA. Using the same single <header> component for both contexts is like wearing the same shoes to the gym and a job interview.
This article walks through 8 concrete header variants you can drop into a React + Tailwind project. Each one covers a specific context: SaaS dashboards, landing pages, documentation sites, ecommerce storefronts. No filler. Real code.
Variant 1 — Minimal Sticky App Header
This is the workhorse for SaaS dashboards and admin panels. Fixed at the top, z-index: 50, with a subtle border-bottom on scroll. The key thing most implementations get wrong: the sticky state should be triggered by scroll position, not by a CSS position: sticky alone, because sticky can't add the border-bottom or background opacity change.
import { useEffect, useState } from 'react';
export function StickyAppHeader() {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
window.addEventListener('scroll', onScroll, { passive: true });
return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
<header
className={[
'fixed top-0 left-0 right-0 z-50 h-14 px-6 flex items-center justify-between',
'bg-white dark:bg-zinc-900 transition-shadow duration-200',
scrolled ? 'shadow-sm border-b border-zinc-200 dark:border-zinc-800' : '',
].join(' ')}
>
<span className="font-semibold text-sm tracking-tight">YourApp</span>
<nav className="flex items-center gap-4 text-sm text-zinc-600 dark:text-zinc-400">
<a href="/dashboard">Dashboard</a>
<a href="/settings">Settings</a>
<button className="ml-2 px-3 py-1.5 rounded-md bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 text-xs font-medium">
Upgrade
</button>
</nav>
</header>
);
}The passive: true option on the scroll listener is not optional on mobile — skip it and you'll see jank. The h-14 (56px) height gives enough touch target area without eating vertical space. Pair this with a pt-14 on your main content wrapper to prevent content from hiding under the fixed header.
Variant 2 — Glassmorphic Header for Dark Landing Pages
If you've built any landing page in the last two years, you've seen this style: a header with a blurred glass background sitting over a gradient or image hero. It reads as premium and it's surprisingly easy to build. The tricky part is the backdrop-filter browser support story — you still need a solid fallback for environments where it's unsupported.
The recipe: background: rgba(10, 10, 10, 0.6) for the tinted glass, backdrop-filter: blur(12px) for the frost, and a border-bottom: 1px solid rgba(255,255,255,0.08) for the subtle edge. If you want to go deeper on the technique, what is glassmorphism covers the full CSS mechanics and browser compatibility matrix.
One thing worth noting: backdrop-filter only blurs content *behind* the element in the stacking context. If your header sits above a static solid color, the effect is invisible. You need a visually complex background — gradient, image, video, or animated canvas — for the blur to be perceptible.
Variant 3 — Full-Width Hero Header with CTA
Marketing pages and product launches need a header that *is* the above-fold experience. Not a nav bar sitting on top of a hero section — the header and hero are one fused element. Logo and nav float at the top, headline and CTA fill the center, and there's usually a background gradient or illustration underneath the whole thing.
The structural trick here is min-h-screen on the header element itself and flex flex-col to let the nav and the hero content stack vertically. The nav is absolute top-0 or a flex child with flex-none. This avoids the common mistake of wrapping a <header> and a <section> separately, which makes coordinating backgrounds a nightmare.
Pair this with an animated button for the primary CTA. A static button in a motion-forward hero looks like it was left behind during a refactor. Small motion details — a pulse, a shimmer, a hover lift — tell the visitor the page is alive.
Variant 4 — Split Header with Left Nav and Right Actions
The split layout is common in developer tools and documentation sites. Left side: logo + primary navigation. Right side: search, theme toggle, GitHub star count, CTA button. The two sides are separated visually, which creates a natural reading flow — brand identity on the left, utility on the right.
export function SplitHeader() {
return (
<header className="w-full border-b border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950">
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between gap-8">
{/* Left */}
<div className="flex items-center gap-6">
<a href="/" className="font-bold text-base">Docs</a>
<nav className="hidden md:flex items-center gap-5 text-sm text-zinc-600 dark:text-zinc-400">
<a href="/components">Components</a>
<a href="/guides">Guides</a>
<a href="/changelog">Changelog</a>
</nav>
</div>
{/* Right */}
<div className="flex items-center gap-3">
<input
type="search"
placeholder="Search..."
className="hidden lg:block text-sm px-3 py-1.5 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-900 w-44 focus:outline-none focus:ring-2 focus:ring-zinc-400"
/>
<a
href="https://github.com"
className="text-sm text-zinc-500 hover:text-zinc-900 dark:hover:text-white"
>
GitHub
</a>
<button className="text-sm px-3 py-1.5 rounded-md bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 font-medium">
Get started
</button>
</div>
</div>
</header>
);
}The hidden md:flex on the nav and hidden lg:block on the search input is intentional. On mobile, you don't want the full horizontal nav collapsing awkwardly — those breakpoints are your escape hatch before you build the mobile hamburger menu. A proper mobile nav is its own component, ideally a theme-aware drawer that slides in from the right.
Variant 5 — Transparent Header That Transitions on Scroll
This is the pattern every agency landing page uses and for good reason: start transparent (so the hero image bleeds to the edges), then transition to a solid or frosted background once the user scrolls past the fold. It feels intentional and polished without much code.
The scroll threshold matters more than you'd think. Triggering the background transition at scrollY > 0 is too aggressive — a 1px scroll fires the handler and the header flickers. Use scrollY > 64 or whatever the approximate height of your hero text block is. That way the transition feels deliberate, not reactive.
Keep the transition duration at 200ms to 300ms. Longer feels sluggish. Shorter feels like a bug. The property you're transitioning is background-color and backdrop-filter — both are GPU-composited on modern browsers, so you won't pay a layout cost for animating them.
Variant 6 — Ecommerce Header with Cart Icon and Search
Ecommerce headers have specific requirements that generic UI patterns don't cover. You need: logo center or left, category navigation, search bar (often center-aligned on desktop), cart icon with item count badge, and user account menu. That's five distinct zones competing for 64–80px of vertical space.
The cart badge is where developers almost always make a subtle mistake. The count is usually rendered as position: absolute over the cart icon, with a fixed min-width to prevent layout shift when it changes from '9' to '10'. Use min-w-[18px] in Tailwind v4.0.2 and a text-[10px] for the numeral. Center it with flex items-center justify-center. Don't use right-0 top-0 — offset it by -6px in both axes so it sits over the corner of the icon.
Does your ecommerce header need to support mega-menus? That's a whole separate problem. The hover state for showing a full-width dropdown panel needs careful z-index management and a pointer-events guard so the menu doesn't collapse when the user moves their cursor from the trigger to the panel content. Worth building this as a headless component before you style it.
Variant 7 — Centered Logo Header for Brand-First Pages
Some brands want the logo dead center with symmetric navigation on both sides — the hotel website pattern, also popular for fashion and luxury SaaS. It looks great but it's harder to make responsive. On mobile, the symmetric layout collapses entirely and you're back to a standard left-logo, right-hamburger structure.
The desktop version uses a three-column grid: grid-cols-[1fr_auto_1fr]. Left nav in column 1, logo in column 2 (justify-self-center), right actions in column 3 (justify-self-end). This is cleaner than trying to fake symmetry with absolute positioning or magic numbers. Grid handles the centering math for you.
Combine this with a marquee component just below the header for a promotional banner (sale, launch announcement, beta notice). The marquee sits between the header and the hero, inheriting the same background, and creates a natural visual speed bump before the main content.
Variant 8 — Collapsible Sidebar + Top Header Combo
For complex apps — analytics dashboards, CMS tools, dev environments — a horizontal top header paired with a vertical sidebar is the standard layout. The top header handles global actions (account, notifications, search) while the sidebar handles the primary navigation tree. They have to coordinate visually without competing.
The practical detail that trips people up: the sidebar's z-index. The top header should always be above the sidebar (z-50 vs z-40) so that any header dropdowns render over the sidebar panel. On mobile, the sidebar collapses to an off-canvas drawer and the header gets a hamburger to open it. The transition between these states needs to account for the sidebar width in the main content's left padding — usually pl-64 to pl-0 with a CSS transition.
If your app uses tabs for secondary navigation within views, consider an animated tabs component inside the main content area rather than adding a third navigation tier. Three navigation layers is the point where users start to get lost, regardless of how logical your information architecture looks in a Figma file.
FAQ
Add a top padding to your main content wrapper that matches the header height. For a h-14 (56px) header, use pt-14 on the <main> element. If the header height changes responsively, use a CSS custom property — --header-height: 56px — and reference it with padding-top: var(--header-height) in your main wrapper.
A common scale: header at z-50, sidebar at z-40, dropdown menus at z-50 (same as header, since they're children), modal backdrop at z-60, modal panel at z-70, toast notifications at z-80. Tailwind's default z-index scale goes to 50, so define custom values in your tailwind.config.js for anything above that.
Yes. Browser support for backdrop-filter is solid across Chrome, Edge, Firefox (since v103), and Safari. The main edge case is Firefox on Linux with hardware acceleration disabled — the property silently falls back to no blur. Add @supports not (backdrop-filter: blur(1px)) { background: rgba(10,10,10,0.95); } to ensure the header remains readable on those environments.
Use a motion.div from Framer Motion as a shared layout element (or use CSS transition on a transform: scaleX() pseudo-element). The Framer Motion approach with layoutId is cleaner for dynamic routes because it animates automatically when the active item changes. Set layoutId='nav-indicator' on the underline span and Framer handles the interpolation between positions.
It depends on the app type. For marketing sites and docs, a hamburger menu (slide-in drawer) is standard and expected. For mobile-first apps with 4-5 primary destinations, a bottom tab bar outperforms a hamburger — it's faster to reach with a thumb. Don't try to replicate your desktop header nav on mobile; redesign the navigation pattern for the context.
Add a visually hidden <a href='#main-content'>Skip to main content</a> as the very first element inside <body>, before the header. Style it with sr-only (Tailwind) by default and not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-[100] on focus. This gives keyboard users a way to bypass the navigation on every page load without affecting visual design.