05 / 22
All 22 in 22 Tailwind CSS Headers
- 01Tailwind CSS Command Palette Header with ⌘K Shortcut
- 02Tailwind Docs Header with Version Switcher and Search
- 03Tailwind SaaS App Header with Workspace Switcher
- 04Tailwind E-Commerce Header with Cart, Wishlist and Mega Menu
- 05Tailwind Marketing Header with Sticky CTA on Scroll
- 06Tailwind Article Header with Reading Progress Bar
- 07Tailwind Centered Logo Editorial Header
- 08Tailwind Transparent Header Over Hero Image
- 09Tailwind Header with Breadcrumb Navigation
- 10Tailwind Header with Notification Dropdown and User Menu
- 11Tailwind Header with GitHub Star Button
- 12Tailwind Sticky Header on Scroll with Scroll-Driven Animation
- 13Tailwind Mega Menu Header with CSS Grid
- 14Tailwind Navbar with Centered Links — Three Column Flexbox
- 15Tailwind Full Screen Menu Overlay with Hamburger Toggle
- 16Tailwind Glassmorphism Header with Backdrop Blur
- 17Tailwind Header with Dismissible Announcement Bar
- 18Tailwind Two Row Header with Top Utility Bar
- 19Tailwind Navbar Link Hover Effects — 5 Animated Styles
- 20Tailwind Sidebar Layout with Collapsible Navigation
- 21Tailwind Multi Level Dropdown Menu Header
- 22Tailwind Shrinking Header on Scroll
Tailwind Marketing Header with Sticky CTA on Scroll
A landing-page header that stays quiet until it has earned the ask: logo, nav and a text link at rest, then a solid Start free trial button slides in once the reader passes 240 px. It is a custom @utility on a scroll(root) timeline — no scroll listener — and where scroll-driven animation is unsupported the button is simply visible from the start.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<div class="thd-05 group/thd05 w-full min-h-svh bg-thd05-bg font-thd05-sans text-thd05-ink antialiased">
<a href="#thd-05-main" class="sr-only focus:not-sr-only focus:absolute focus:left-3 focus:top-3 focus:z-[60] focus:rounded-lg focus:bg-thd05-acc focus:px-4 focus:py-2.5 focus:text-sm focus:font-semibold focus:text-white">Skip to content</a>
<div class="sticky top-0 z-40 px-3 pt-3">
<header class="mx-auto flex max-w-5xl items-center gap-3 rounded-full border border-thd05-line bg-thd05-panel/85 py-1.5 pl-5 pr-1.5 shadow-[0_10px_40px_-20px_rgb(0_0_0/.25)] backdrop-blur-xl">
<a href="#thd-05-main" class="flex items-center gap-2 text-lg font-extrabold tracking-tight"><span aria-hidden="true" class="flex gap-[3px]"><span class="h-4 w-1 rounded-full bg-thd05-acc"></span><span class="h-4 w-1 translate-y-1 rounded-full bg-thd05-acc/60"></span><span class="h-4 w-1 rounded-full bg-thd05-acc/30"></span></span>Cadence</a>
<nav aria-label="Main" class="mx-auto hidden md:block">
<ul class="flex items-center gap-1 text-[15px] font-medium">
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Platform</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Customers</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Pricing</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Resources</a></li>
</ul>
</nav>
<div class="ml-auto flex items-center gap-1 md:ml-0">
<input id="thd-05-t" type="checkbox" class="peer/t sr-only">
<label for="thd-05-t" class="grid size-11 cursor-pointer place-items-center rounded-full text-thd05-mut hover:bg-thd05-ink/5 hover:text-thd05-ink peer-focus-visible/t:outline-2 peer-focus-visible/t:outline-thd05-acc">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true" class="size-[18px] group-has-[#thd-05-t:checked]/thd05:hidden"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5a8.6 8.6 0 1 0 10.9 10.9Z"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true" class="hidden size-[18px] group-has-[#thd-05-t:checked]/thd05:block"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.8v2.1M12 19.1v2.1M2.8 12h2.1M19.1 12h2.1M5.5 5.5 7 7M17 17l1.5 1.5M18.5 5.5 17 7M7 17l-1.5 1.5"/></svg>
<span class="sr-only">Switch light or dark theme</span>
</label>
<a href="#thd-05-main" class="thd05-shrink hidden rounded-full px-3 py-2 text-[15px] font-semibold sm:block">Sign in</a>
<a href="#thd-05-main" class="thd05-reveal flex min-h-11 items-center gap-1.5 whitespace-nowrap rounded-full bg-thd05-acc px-5 text-[15px] font-bold text-white shadow-[0_8px_24px_-8px_var(--color-thd05-acc)] transition-[filter] hover:brightness-110">Start free trial <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-4"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
</div>
</header>
</div>
<main id="thd-05-main" class="mx-auto max-w-5xl px-5 pb-20 pt-[clamp(3.5rem,11vw,7rem)] text-center">
<p class="mx-auto inline-flex rounded-full bg-thd05-acc/10 px-3 py-1 text-sm font-semibold text-thd05-acc">Scroll 240px ↓</p>
<h1 class="mx-auto mt-5 max-w-[16ch] text-[clamp(2.4rem,7.5vw,5rem)] font-extrabold leading-[.98] tracking-[-.04em] text-balance">Meetings that end with a decision.</h1>
<p class="mx-auto mt-5 max-w-[48ch] text-lg text-thd05-mut text-pretty">Watch the header: the trial button waits until you have read this far, then slides in as <em>Sign in</em> steps aside.</p>
<div class="mx-auto mt-14 grid max-w-4xl gap-3 text-left sm:grid-cols-3">
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">31%</p><p class="mt-1 text-sm text-thd05-mut">fewer follow-up meetings</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">4.8/5</p><p class="mt-1 text-sm text-thd05-mut">average G2 rating</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">12 min</p><p class="mt-1 text-sm text-thd05-mut">to first agenda</p></div>
</div>
<div aria-hidden="true" class="h-[90svh]"></div>
</main>
</div><div class="thd-05 group/thd05 w-full min-h-svh bg-thd05-bg font-thd05-sans text-thd05-ink antialiased">
<a href="#thd-05-main" class="sr-only focus:not-sr-only focus:absolute focus:left-3 focus:top-3 focus:z-[60] focus:rounded-lg focus:bg-thd05-acc focus:px-4 focus:py-2.5 focus:text-sm focus:font-semibold focus:text-white">Skip to content</a>
<div class="sticky top-0 z-40 px-3 pt-3">
<header class="mx-auto flex max-w-5xl items-center gap-3 rounded-full border border-thd05-line bg-thd05-panel/85 py-1.5 pl-5 pr-1.5 shadow-[0_10px_40px_-20px_rgb(0_0_0/.25)] backdrop-blur-xl">
<a href="#thd-05-main" class="flex items-center gap-2 text-lg font-extrabold tracking-tight"><span aria-hidden="true" class="flex gap-[3px]"><span class="h-4 w-1 rounded-full bg-thd05-acc"></span><span class="h-4 w-1 translate-y-1 rounded-full bg-thd05-acc/60"></span><span class="h-4 w-1 rounded-full bg-thd05-acc/30"></span></span>Cadence</a>
<nav aria-label="Main" class="mx-auto hidden md:block">
<ul class="flex items-center gap-1 text-[15px] font-medium">
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Platform</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Customers</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Pricing</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Resources</a></li>
</ul>
</nav>
<div class="ml-auto flex items-center gap-1 md:ml-0">
<input id="thd-05-t" type="checkbox" class="peer/t sr-only">
<label for="thd-05-t" class="grid size-11 cursor-pointer place-items-center rounded-full text-thd05-mut hover:bg-thd05-ink/5 hover:text-thd05-ink peer-focus-visible/t:outline-2 peer-focus-visible/t:outline-thd05-acc">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true" class="size-[18px] group-has-[#thd-05-t:checked]/thd05:hidden"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5a8.6 8.6 0 1 0 10.9 10.9Z"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true" class="hidden size-[18px] group-has-[#thd-05-t:checked]/thd05:block"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.8v2.1M12 19.1v2.1M2.8 12h2.1M19.1 12h2.1M5.5 5.5 7 7M17 17l1.5 1.5M18.5 5.5 17 7M7 17l-1.5 1.5"/></svg>
<span class="sr-only">Switch light or dark theme</span>
</label>
<a href="#thd-05-main" class="thd05-shrink hidden rounded-full px-3 py-2 text-[15px] font-semibold sm:block">Sign in</a>
<a href="#thd-05-main" class="thd05-reveal flex min-h-11 items-center gap-1.5 whitespace-nowrap rounded-full bg-thd05-acc px-5 text-[15px] font-bold text-white shadow-[0_8px_24px_-8px_var(--color-thd05-acc)] transition-[filter] hover:brightness-110">Start free trial <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-4"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
</div>
</header>
</div>
<main id="thd-05-main" class="mx-auto max-w-5xl px-5 pb-20 pt-[clamp(3.5rem,11vw,7rem)] text-center">
<p class="mx-auto inline-flex rounded-full bg-thd05-acc/10 px-3 py-1 text-sm font-semibold text-thd05-acc">Scroll 240px ↓</p>
<h1 class="mx-auto mt-5 max-w-[16ch] text-[clamp(2.4rem,7.5vw,5rem)] font-extrabold leading-[.98] tracking-[-.04em] text-balance">Meetings that end with a decision.</h1>
<p class="mx-auto mt-5 max-w-[48ch] text-lg text-thd05-mut text-pretty">Watch the header: the trial button waits until you have read this far, then slides in as <em>Sign in</em> steps aside.</p>
<div class="mx-auto mt-14 grid max-w-4xl gap-3 text-left sm:grid-cols-3">
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">31%</p><p class="mt-1 text-sm text-thd05-mut">fewer follow-up meetings</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">4.8/5</p><p class="mt-1 text-sm text-thd05-mut">average G2 rating</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">12 min</p><p class="mt-1 text-sm text-thd05-mut">to first agenda</p></div>
</div>
<div aria-hidden="true" class="h-[90svh]"></div>
</main>
</div>@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The CSS original's
@supportsblock of five rules became two custom utilities used like any class — the markup saysthd05-revealwhere the behaviour lives. - Every other declaration — the pill bar, the blur, the stats — is a utility.
- UI upgrade from the CSS original: the full-width bar became a floating pill with a soft shadow, and the CTA gained an arrow and a tinted glow.
- UI upgrade: Sign in now dims as the CTA arrives so the two never compete, and reduced-motion users get the CTA at rest with no slide.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Marketing Header with Sticky CTA on Scroll
Source: https://codefronts.com/layouts/tailwind-css-headers/tailwind-marketing-header-sticky-cta-on-scroll/
A landing-page header that stays quiet until it has earned the ask: logo, nav and a text link at rest, then a solid Start free trial button slides in once the reader passes 240 px. It is a custom @utility on a scroll(root) timeline — no scroll listener — and where scroll-driven animation is unsupported the button is simply visible from the start.
## HTML
```html
<div class="thd-05 group/thd05 w-full min-h-svh bg-thd05-bg font-thd05-sans text-thd05-ink antialiased">
<a href="#thd-05-main" class="sr-only focus:not-sr-only focus:absolute focus:left-3 focus:top-3 focus:z-[60] focus:rounded-lg focus:bg-thd05-acc focus:px-4 focus:py-2.5 focus:text-sm focus:font-semibold focus:text-white">Skip to content</a>
<div class="sticky top-0 z-40 px-3 pt-3">
<header class="mx-auto flex max-w-5xl items-center gap-3 rounded-full border border-thd05-line bg-thd05-panel/85 py-1.5 pl-5 pr-1.5 shadow-[0_10px_40px_-20px_rgb(0_0_0/.25)] backdrop-blur-xl">
<a href="#thd-05-main" class="flex items-center gap-2 text-lg font-extrabold tracking-tight"><span aria-hidden="true" class="flex gap-[3px]"><span class="h-4 w-1 rounded-full bg-thd05-acc"></span><span class="h-4 w-1 translate-y-1 rounded-full bg-thd05-acc/60"></span><span class="h-4 w-1 rounded-full bg-thd05-acc/30"></span></span>Cadence</a>
<nav aria-label="Main" class="mx-auto hidden md:block">
<ul class="flex items-center gap-1 text-[15px] font-medium">
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Platform</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Customers</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Pricing</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Resources</a></li>
</ul>
</nav>
<div class="ml-auto flex items-center gap-1 md:ml-0">
<input id="thd-05-t" type="checkbox" class="peer/t sr-only">
<label for="thd-05-t" class="grid size-11 cursor-pointer place-items-center rounded-full text-thd05-mut hover:bg-thd05-ink/5 hover:text-thd05-ink peer-focus-visible/t:outline-2 peer-focus-visible/t:outline-thd05-acc">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true" class="size-[18px] group-has-[#thd-05-t:checked]/thd05:hidden"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5a8.6 8.6 0 1 0 10.9 10.9Z"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true" class="hidden size-[18px] group-has-[#thd-05-t:checked]/thd05:block"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.8v2.1M12 19.1v2.1M2.8 12h2.1M19.1 12h2.1M5.5 5.5 7 7M17 17l1.5 1.5M18.5 5.5 17 7M7 17l-1.5 1.5"/></svg>
<span class="sr-only">Switch light or dark theme</span>
</label>
<a href="#thd-05-main" class="thd05-shrink hidden rounded-full px-3 py-2 text-[15px] font-semibold sm:block">Sign in</a>
<a href="#thd-05-main" class="thd05-reveal flex min-h-11 items-center gap-1.5 whitespace-nowrap rounded-full bg-thd05-acc px-5 text-[15px] font-bold text-white shadow-[0_8px_24px_-8px_var(--color-thd05-acc)] transition-[filter] hover:brightness-110">Start free trial <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-4"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
</div>
</header>
</div>
<main id="thd-05-main" class="mx-auto max-w-5xl px-5 pb-20 pt-[clamp(3.5rem,11vw,7rem)] text-center">
<p class="mx-auto inline-flex rounded-full bg-thd05-acc/10 px-3 py-1 text-sm font-semibold text-thd05-acc">Scroll 240px ↓</p>
<h1 class="mx-auto mt-5 max-w-[16ch] text-[clamp(2.4rem,7.5vw,5rem)] font-extrabold leading-[.98] tracking-[-.04em] text-balance">Meetings that end with a decision.</h1>
<p class="mx-auto mt-5 max-w-[48ch] text-lg text-thd05-mut text-pretty">Watch the header: the trial button waits until you have read this far, then slides in as <em>Sign in</em> steps aside.</p>
<div class="mx-auto mt-14 grid max-w-4xl gap-3 text-left sm:grid-cols-3">
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">31%</p><p class="mt-1 text-sm text-thd05-mut">fewer follow-up meetings</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">4.8/5</p><p class="mt-1 text-sm text-thd05-mut">average G2 rating</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">12 min</p><p class="mt-1 text-sm text-thd05-mut">to first agenda</p></div>
</div>
<div aria-hidden="true" class="h-[90svh]"></div>
</main>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Marketing Header with Sticky CTA on Scroll
Source: https://codefronts.com/layouts/tailwind-css-headers/tailwind-marketing-header-sticky-cta-on-scroll/
A landing-page header that stays quiet until it has earned the ask: logo, nav and a text link at rest, then a solid Start free trial button slides in once the reader passes 240 px. It is a custom @utility on a scroll(root) timeline — no scroll listener — and where scroll-driven animation is unsupported the button is simply visible from the start.
## HTML
```html
<div class="thd-05 group/thd05 w-full min-h-svh bg-thd05-bg font-thd05-sans text-thd05-ink antialiased">
<a href="#thd-05-main" class="sr-only focus:not-sr-only focus:absolute focus:left-3 focus:top-3 focus:z-[60] focus:rounded-lg focus:bg-thd05-acc focus:px-4 focus:py-2.5 focus:text-sm focus:font-semibold focus:text-white">Skip to content</a>
<div class="sticky top-0 z-40 px-3 pt-3">
<header class="mx-auto flex max-w-5xl items-center gap-3 rounded-full border border-thd05-line bg-thd05-panel/85 py-1.5 pl-5 pr-1.5 shadow-[0_10px_40px_-20px_rgb(0_0_0/.25)] backdrop-blur-xl">
<a href="#thd-05-main" class="flex items-center gap-2 text-lg font-extrabold tracking-tight"><span aria-hidden="true" class="flex gap-[3px]"><span class="h-4 w-1 rounded-full bg-thd05-acc"></span><span class="h-4 w-1 translate-y-1 rounded-full bg-thd05-acc/60"></span><span class="h-4 w-1 rounded-full bg-thd05-acc/30"></span></span>Cadence</a>
<nav aria-label="Main" class="mx-auto hidden md:block">
<ul class="flex items-center gap-1 text-[15px] font-medium">
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Platform</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Customers</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Pricing</a></li>
<li><a href="#thd-05-main" class="rounded-full px-3 py-2 text-thd05-mut transition-colors hover:bg-thd05-ink/5 hover:text-thd05-ink">Resources</a></li>
</ul>
</nav>
<div class="ml-auto flex items-center gap-1 md:ml-0">
<input id="thd-05-t" type="checkbox" class="peer/t sr-only">
<label for="thd-05-t" class="grid size-11 cursor-pointer place-items-center rounded-full text-thd05-mut hover:bg-thd05-ink/5 hover:text-thd05-ink peer-focus-visible/t:outline-2 peer-focus-visible/t:outline-thd05-acc">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true" class="size-[18px] group-has-[#thd-05-t:checked]/thd05:hidden"><path d="M20.5 14.4A8.4 8.4 0 0 1 9.6 3.5a8.6 8.6 0 1 0 10.9 10.9Z"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true" class="hidden size-[18px] group-has-[#thd-05-t:checked]/thd05:block"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.8v2.1M12 19.1v2.1M2.8 12h2.1M19.1 12h2.1M5.5 5.5 7 7M17 17l1.5 1.5M18.5 5.5 17 7M7 17l-1.5 1.5"/></svg>
<span class="sr-only">Switch light or dark theme</span>
</label>
<a href="#thd-05-main" class="thd05-shrink hidden rounded-full px-3 py-2 text-[15px] font-semibold sm:block">Sign in</a>
<a href="#thd-05-main" class="thd05-reveal flex min-h-11 items-center gap-1.5 whitespace-nowrap rounded-full bg-thd05-acc px-5 text-[15px] font-bold text-white shadow-[0_8px_24px_-8px_var(--color-thd05-acc)] transition-[filter] hover:brightness-110">Start free trial <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="size-4"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
</div>
</header>
</div>
<main id="thd-05-main" class="mx-auto max-w-5xl px-5 pb-20 pt-[clamp(3.5rem,11vw,7rem)] text-center">
<p class="mx-auto inline-flex rounded-full bg-thd05-acc/10 px-3 py-1 text-sm font-semibold text-thd05-acc">Scroll 240px ↓</p>
<h1 class="mx-auto mt-5 max-w-[16ch] text-[clamp(2.4rem,7.5vw,5rem)] font-extrabold leading-[.98] tracking-[-.04em] text-balance">Meetings that end with a decision.</h1>
<p class="mx-auto mt-5 max-w-[48ch] text-lg text-thd05-mut text-pretty">Watch the header: the trial button waits until you have read this far, then slides in as <em>Sign in</em> steps aside.</p>
<div class="mx-auto mt-14 grid max-w-4xl gap-3 text-left sm:grid-cols-3">
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">31%</p><p class="mt-1 text-sm text-thd05-mut">fewer follow-up meetings</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">4.8/5</p><p class="mt-1 text-sm text-thd05-mut">average G2 rating</p></div>
<div class="rounded-3xl bg-thd05-panel p-6 shadow-sm ring-1 ring-thd05-line"><p class="text-3xl font-extrabold tabular-nums text-thd05-acc">12 min</p><p class="mt-1 text-sm text-thd05-mut">to first agenda</p></div>
</div>
<div aria-hidden="true" class="h-[90svh]"></div>
</main>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme inline {
--color-thd05-bg: var(--thd05-bg);
--color-thd05-panel: var(--thd05-panel);
--color-thd05-ink: var(--thd05-ink);
--color-thd05-mut: var(--thd05-mut);
--color-thd05-line: var(--thd05-line);
--color-thd05-acc: var(--thd05-acc);
}
@theme {
--font-thd05-sans: 'Bricolage Grotesque', system-ui, sans-serif;
}
.thd-05 {
width: 100%;
min-height: 100svh;
--thd05-bg: #fbf8f3;
--thd05-panel: #ffffff;
--thd05-ink: #1c1917;
--thd05-mut: #5c544d;
--thd05-line: rgb(28 25 23 / 0.08);
--thd05-acc: #e0480f;
}
.thd-05:has(#thd-05-t:checked) {
--thd05-bg: #121010;
--thd05-panel: #1c1917;
--thd05-ink: #f6f1ec;
--thd05-mut: #b0a79f;
--thd05-line: rgb(255 255 255 / 0.09);
--thd05-acc: #ff6a33;
}
/* Scroll-driven utilities: shorthand first, timeline second — one utility guarantees the order. */
@utility thd05-reveal {
@supports (animation-timeline: scroll()) {
animation: thd05-reveal linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@utility thd05-shrink {
@supports (animation-timeline: scroll()) {
animation: thd05-shrink linear both;
animation-timeline: scroll(root);
animation-range: 200px 280px;
}
}
@keyframes thd05-reveal {
from {
opacity: 0;
translate: 1.5rem 0;
scale: 0.92;
}
}
@keyframes thd05-shrink {
to {
opacity: 0.55;
}
}
@media (prefers-reduced-motion: reduce) {
.thd05-reveal {
animation: none !important;
}
}
```How this works
Why a custom utility. A scroll-driven animation needs animation-timeline after the animation shorthand, because the shorthand resets it. Tailwind cannot guarantee the order of two separate utilities, so the three declarations live in one @utility — used in markup like any other class.
The fallback is the default. Outside the @supports block the CTA has no animation, so browsers without scroll timelines show it from the first paint — the conversion button is never missing.
Make it yours
- Reveal point: change
animation-range: 200px 280pxin the utility. - Always-visible on mobile: add
max-sm:animate-noneto the CTA. - Swap the pill for a full-width bar by removing
max-w-5xl rounded-full.
Gotchas — read before shipping
- The hidden CTA is still in the tab order — that is deliberate: keyboard users can reach it at any scroll position.
- Scroll timelines follow the nearest scroll container; if your page scrolls inside a wrapper, use
scroll(nearest).
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 115+ | 26+ | 128+ (static) | 115+ |
Scroll-driven reveal in Chrome/Edge 115+ and Safari 26. Firefox shows the CTA from the start.