Tailwind + JSMIT licensed

Tailwind Announcement Bar Dual Navbar

The e-commerce header stack: promo strip, utility row, main nav. The port upgrades the dismiss from an instant display:none to an animated collapse — grid-rows-[1fr] to grid-rows-[0fr], the modern height-transition idiom — and remembers the dismissal in localStorage.

Live Demo
Plain CSSTailwind v4
Try it

Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49

Cruip · Affiliate link

Browse Cruip templates

The code

<div class="tnb-19 group w-full min-h-svh bg-tnb19-page font-tnb19-sans text-tnb19-ink" aria-label="Announcement bar dual navbar demo">
  <input type="checkbox" id="tnb19-menu" class="sr-only peer" aria-label="Toggle navigation menu">
  <header class="sticky top-0 z-100">
    <div id="tnb19-promo" class="grid grid-rows-[1fr] bg-tnb19-promo transition-[grid-template-rows] duration-300 data-dismissed:grid-rows-[0fr] motion-reduce:transition-none">
      <div class="relative flex items-center justify-center gap-3 overflow-hidden px-10 py-2 text-[13px] font-medium text-white">
        <span aria-hidden="true">&#127881;</span>
        <p>Summer sale &mdash; up to 40% off everything. <a href="#shop" class="font-bold text-white underline underline-offset-2 hover:opacity-80">Shop now &rarr;</a></p>
        <button type="button" id="tnb19-dismiss" aria-label="Dismiss announcement" class="absolute top-1/2 right-3 grid size-6 -translate-y-1/2 cursor-pointer place-items-center rounded-full border-0 bg-white/20 text-sm text-white transition-colors hover:bg-white/35">&times;</button>
      </div>
    </div>
    <div class="flex items-center justify-between border-b border-tnb19-edge bg-tnb19-util px-8 py-1 text-xs font-medium text-tnb19-mut max-md:hidden">
      <div class="flex gap-5">
        <span class="flex items-center gap-1"><span aria-hidden="true">&#128205;</span>Free shipping over $50</span>
        <span class="flex items-center gap-1"><span aria-hidden="true">&#128274;</span>Secure checkout</span>
      </div>
      <div class="flex items-center gap-5">
        <a href="#help" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">Help</a>
        <a href="#track" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">Track order</a>
        <a href="#lang" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">English &#9662;</a>
      </div>
    </div>
    <nav class="flex h-16 items-center gap-6 border-b border-tnb19-edge bg-white px-5 md:px-8" aria-label="Primary">
      <a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.03em] text-tnb19-ink no-underline">Stock<span class="text-tnb19-acc">pile</span></a>
      <ul class="hidden flex-1 list-none items-center gap-0 md:flex">
        <li><a href="#home" aria-current="page" class="block rounded-md px-3.5 py-2 text-sm font-semibold text-tnb19-acc no-underline">Home</a></li>
        <li><a href="#new" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">New arrivals</a></li>
        <li><a href="#collections" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">Collections</a></li>
        <li><a href="#sale" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">Sale</a></li>
        <li><a href="#about" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">About</a></li>
      </ul>
      <div class="ml-auto hidden items-center gap-3 md:flex">
        <a href="#cart" class="relative flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm font-semibold text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink"><span aria-hidden="true">&#128722;</span>Cart<span class="absolute top-0.5 right-0.5 grid size-4 place-items-center rounded-full bg-tnb19-acc text-[10px] font-extrabold text-white ring-2 ring-white">3</span></a>
        <a href="#signin" class="rounded-lg bg-tnb19-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb19-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Sign in</a>
      </div>
      <label for="tnb19-menu" class="ml-auto flex size-11 cursor-pointer flex-col items-center justify-center gap-1.5 md:hidden" aria-hidden="true">
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-transform duration-300 group-has-checked:translate-y-2 group-has-checked:rotate-45 motion-reduce:transition-none"></span>
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-opacity duration-300 group-has-checked:opacity-0 motion-reduce:transition-none"></span>
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-transform duration-300 group-has-checked:-translate-y-2 group-has-checked:-rotate-45 motion-reduce:transition-none"></span>
      </label>
    </nav>
    <div class="hidden border-b border-tnb19-edge bg-white px-5 py-2 max-md:group-has-checked:grid">
      <a href="#home" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-semibold text-tnb19-acc no-underline">Home</a>
      <a href="#new" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">New arrivals</a>
      <a href="#collections" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">Collections</a>
      <a href="#sale" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">Sale</a>
      <a href="#cart" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline">Cart (3)</a>
      <a href="#signin" class="mt-2 flex min-h-11 items-center justify-center rounded-lg bg-tnb19-acc text-sm font-bold text-white no-underline">Sign in</a>
    </div>
  </header>
  <main class="mx-auto max-w-3xl px-5 py-12 md:px-8">
    <h1 class="mb-4 text-4xl font-extrabold tracking-[-0.03em] text-tnb19-ink">Announcement + Dual Navbar</h1>
    <p class="text-lg leading-relaxed text-tnb19-mut">Dismiss the promo: it collapses rather than vanishing, because the strip is a one-row grid animating <code class="rounded bg-tnb19-hover px-1.5 py-0.5 text-[0.9em]">grid-rows-[1fr]</code> to <code class="rounded bg-tnb19-hover px-1.5 py-0.5 text-[0.9em]">grid-rows-[0fr]</code>. Reload — it stays dismissed.</p>
  </main>
</div>
@import "tailwindcss";

@theme {
  --color-tnb19-page: #fbfbfc;
  --color-tnb19-page: oklch(0.99 0.002 280);
  --color-tnb19-ink: #141418;
  --color-tnb19-ink: oklch(0.2 0.005 280);
  --color-tnb19-mut: #6b7280;
  --color-tnb19-mut: oklch(0.55 0.02 265);
  --color-tnb19-edge: #ededf0;
  --color-tnb19-edge: oklch(0.94 0.003 280);
  --color-tnb19-util: #f9f9fa;
  --color-tnb19-util: oklch(0.98 0.002 280);
  --color-tnb19-hover: #f4f4f8;
  --color-tnb19-hover: oklch(0.96 0.004 280);
  --color-tnb19-promo: #6d28d9;
  --color-tnb19-promo: oklch(0.48 0.24 293);
  --color-tnb19-acc: #7c3aed;
  --color-tnb19-acc: oklch(0.53 0.26 295);
  --color-tnb19-accdark: #6d28d9;
  --color-tnb19-accdark: oklch(0.48 0.24 293);
  --font-tnb19-sans: 'Rubik', system-ui, sans-serif;
}

.tnb-19 {
  width: 100%;
  min-height: 100svh;
}

.tnb-19 ::selection {
  background: var(--color-tnb19-acc);
  color: #fff;
}
(function () {
  document.querySelectorAll('.tnb-19').forEach(function (root) {
    if (root.dataset.bound) return; root.dataset.bound = '1';
    var promo = root.querySelector('#tnb19-promo');
    var btn = root.querySelector('#tnb19-dismiss');
    if (!promo || !btn) return;
    var KEY = 'tnb19-promo-dismissed';

    try {
      if (localStorage.getItem(KEY) === '1') {
        promo.style.transition = 'none';
        promo.toggleAttribute('data-dismissed', true);
        requestAnimationFrame(function () { promo.style.transition = ''; });
      }
    } catch (e) { /* storage blocked: show the promo */ }

    btn.addEventListener('click', function () {
      promo.toggleAttribute('data-dismissed', true);
      btn.setAttribute('aria-expanded', 'false');
      try { localStorage.setItem(KEY, '1'); } catch (e) {}
    });
  });
})();

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tnb19-page: #fbfbfc;
  --color-tnb19-page: oklch(0.99 0.002 280);
  --color-tnb19-ink: #141418;
  --color-tnb19-ink: oklch(0.2 0.005 280);
  --color-tnb19-mut: #6b7280;
  --color-tnb19-mut: oklch(0.55 0.02 265);
  --color-tnb19-edge: #ededf0;
  --color-tnb19-edge: oklch(0.94 0.003 280);
  --color-tnb19-util: #f9f9fa;
  --color-tnb19-util: oklch(0.98 0.002 280);
  --color-tnb19-hover: #f4f4f8;
  --color-tnb19-hover: oklch(0.96 0.004 280);
  --color-tnb19-promo: #6d28d9;
  --color-tnb19-promo: oklch(0.48 0.24 293);
  --color-tnb19-acc: #7c3aed;
  --color-tnb19-acc: oklch(0.53 0.26 295);
  --color-tnb19-accdark: #6d28d9;
  --color-tnb19-accdark: oklch(0.48 0.24 293);
  --font-tnb19-sans: 'Rubik', system-ui, sans-serif;
}

.tnb-19 {
  width: 100%;
  min-height: 100svh;
}

.tnb-19 ::selection {
  background: var(--color-tnb19-acc);
  color: #fff;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Rubik:wght@400;500;600;700;800&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The original set display:none on dismiss, which jumps; the port animates grid-template-rows from 1fr to 0fr — the current idiom for collapsing unknown heights.
  • Persistence, listed as a customization idea in the CSS version, is implemented here, including the transition suppression that stops the strip flashing on a return visit.
  • State is a data-dismissed attribute on the strip, so the collapse geometry is declared in the markup and the script only flips the flag.
  • The cart badge switched to ring-2 ring-white, consistent with demos 10 and 13.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Announcement Bar Dual Navbar
Source: https://codefronts.com/navigation/tailwind-css-responsive-navbars/tailwind-announcement-bar-dual-navbar/

The e-commerce header stack: promo strip, utility row, main nav. The port upgrades the dismiss from an instant display:none to an animated collapse — grid-rows-[1fr] to grid-rows-[0fr], the modern height-transition idiom — and remembers the dismissal in localStorage.
## HTML
```html
<div class="tnb-19 group w-full min-h-svh bg-tnb19-page font-tnb19-sans text-tnb19-ink" aria-label="Announcement bar dual navbar demo">
  <input type="checkbox" id="tnb19-menu" class="sr-only peer" aria-label="Toggle navigation menu">
  <header class="sticky top-0 z-100">
    <div id="tnb19-promo" class="grid grid-rows-[1fr] bg-tnb19-promo transition-[grid-template-rows] duration-300 data-dismissed:grid-rows-[0fr] motion-reduce:transition-none">
      <div class="relative flex items-center justify-center gap-3 overflow-hidden px-10 py-2 text-[13px] font-medium text-white">
        <span aria-hidden="true">&#127881;</span>
        <p>Summer sale &mdash; up to 40% off everything. <a href="#shop" class="font-bold text-white underline underline-offset-2 hover:opacity-80">Shop now &rarr;</a></p>
        <button type="button" id="tnb19-dismiss" aria-label="Dismiss announcement" class="absolute top-1/2 right-3 grid size-6 -translate-y-1/2 cursor-pointer place-items-center rounded-full border-0 bg-white/20 text-sm text-white transition-colors hover:bg-white/35">&times;</button>
      </div>
    </div>
    <div class="flex items-center justify-between border-b border-tnb19-edge bg-tnb19-util px-8 py-1 text-xs font-medium text-tnb19-mut max-md:hidden">
      <div class="flex gap-5">
        <span class="flex items-center gap-1"><span aria-hidden="true">&#128205;</span>Free shipping over $50</span>
        <span class="flex items-center gap-1"><span aria-hidden="true">&#128274;</span>Secure checkout</span>
      </div>
      <div class="flex items-center gap-5">
        <a href="#help" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">Help</a>
        <a href="#track" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">Track order</a>
        <a href="#lang" class="text-tnb19-mut no-underline transition-colors hover:text-tnb19-ink">English &#9662;</a>
      </div>
    </div>
    <nav class="flex h-16 items-center gap-6 border-b border-tnb19-edge bg-white px-5 md:px-8" aria-label="Primary">
      <a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.03em] text-tnb19-ink no-underline">Stock<span class="text-tnb19-acc">pile</span></a>
      <ul class="hidden flex-1 list-none items-center gap-0 md:flex">
        <li><a href="#home" aria-current="page" class="block rounded-md px-3.5 py-2 text-sm font-semibold text-tnb19-acc no-underline">Home</a></li>
        <li><a href="#new" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">New arrivals</a></li>
        <li><a href="#collections" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">Collections</a></li>
        <li><a href="#sale" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">Sale</a></li>
        <li><a href="#about" class="block rounded-md px-3.5 py-2 text-sm font-medium text-tnb19-mut no-underline transition-colors duration-150 hover:bg-tnb19-hover hover:text-tnb19-ink">About</a></li>
      </ul>
      <div class="ml-auto hidden items-center gap-3 md:flex">
        <a href="#cart" class="relative flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm font-semibold text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink"><span aria-hidden="true">&#128722;</span>Cart<span class="absolute top-0.5 right-0.5 grid size-4 place-items-center rounded-full bg-tnb19-acc text-[10px] font-extrabold text-white ring-2 ring-white">3</span></a>
        <a href="#signin" class="rounded-lg bg-tnb19-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb19-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Sign in</a>
      </div>
      <label for="tnb19-menu" class="ml-auto flex size-11 cursor-pointer flex-col items-center justify-center gap-1.5 md:hidden" aria-hidden="true">
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-transform duration-300 group-has-checked:translate-y-2 group-has-checked:rotate-45 motion-reduce:transition-none"></span>
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-opacity duration-300 group-has-checked:opacity-0 motion-reduce:transition-none"></span>
        <span class="block h-0.5 w-5.5 rounded-sm bg-tnb19-ink transition-transform duration-300 group-has-checked:-translate-y-2 group-has-checked:-rotate-45 motion-reduce:transition-none"></span>
      </label>
    </nav>
    <div class="hidden border-b border-tnb19-edge bg-white px-5 py-2 max-md:group-has-checked:grid">
      <a href="#home" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-semibold text-tnb19-acc no-underline">Home</a>
      <a href="#new" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">New arrivals</a>
      <a href="#collections" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">Collections</a>
      <a href="#sale" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline transition-colors hover:bg-tnb19-hover hover:text-tnb19-ink">Sale</a>
      <a href="#cart" class="flex min-h-11 items-center rounded-md px-2 text-[15px] font-medium text-tnb19-mut no-underline">Cart (3)</a>
      <a href="#signin" class="mt-2 flex min-h-11 items-center justify-center rounded-lg bg-tnb19-acc text-sm font-bold text-white no-underline">Sign in</a>
    </div>
  </header>
  <main class="mx-auto max-w-3xl px-5 py-12 md:px-8">
    <h1 class="mb-4 text-4xl font-extrabold tracking-[-0.03em] text-tnb19-ink">Announcement + Dual Navbar</h1>
    <p class="text-lg leading-relaxed text-tnb19-mut">Dismiss the promo: it collapses rather than vanishing, because the strip is a one-row grid animating <code class="rounded bg-tnb19-hover px-1.5 py-0.5 text-[0.9em]">grid-rows-[1fr]</code> to <code class="rounded bg-tnb19-hover px-1.5 py-0.5 text-[0.9em]">grid-rows-[0fr]</code>. Reload — it stays dismissed.</p>
  </main>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tnb19-page: #fbfbfc;
  --color-tnb19-page: oklch(0.99 0.002 280);
  --color-tnb19-ink: #141418;
  --color-tnb19-ink: oklch(0.2 0.005 280);
  --color-tnb19-mut: #6b7280;
  --color-tnb19-mut: oklch(0.55 0.02 265);
  --color-tnb19-edge: #ededf0;
  --color-tnb19-edge: oklch(0.94 0.003 280);
  --color-tnb19-util: #f9f9fa;
  --color-tnb19-util: oklch(0.98 0.002 280);
  --color-tnb19-hover: #f4f4f8;
  --color-tnb19-hover: oklch(0.96 0.004 280);
  --color-tnb19-promo: #6d28d9;
  --color-tnb19-promo: oklch(0.48 0.24 293);
  --color-tnb19-acc: #7c3aed;
  --color-tnb19-acc: oklch(0.53 0.26 295);
  --color-tnb19-accdark: #6d28d9;
  --color-tnb19-accdark: oklch(0.48 0.24 293);
  --font-tnb19-sans: 'Rubik', system-ui, sans-serif;
}

.tnb-19 {
  width: 100%;
  min-height: 100svh;
}

.tnb-19 ::selection {
  background: var(--color-tnb19-acc);
  color: #fff;
}
```

## JavaScript
```js
(function () {
  document.querySelectorAll('.tnb-19').forEach(function (root) {
    if (root.dataset.bound) return; root.dataset.bound = '1';
    var promo = root.querySelector('#tnb19-promo');
    var btn = root.querySelector('#tnb19-dismiss');
    if (!promo || !btn) return;
    var KEY = 'tnb19-promo-dismissed';

    try {
      if (localStorage.getItem(KEY) === '1') {
        promo.style.transition = 'none';
        promo.toggleAttribute('data-dismissed', true);
        requestAnimationFrame(function () { promo.style.transition = ''; });
      }
    } catch (e) { /* storage blocked: show the promo */ }

    btn.addEventListener('click', function () {
      promo.toggleAttribute('data-dismissed', true);
      btn.setAttribute('aria-expanded', 'false');
      try { localStorage.setItem(KEY, '1'); } catch (e) {}
    });
  });
})();
```

How this works

Collapse without a fixed height. max-height transitions need a guessed ceiling; a one-row grid does not:

<div class="grid grid-rows-[1fr] transition-[grid-template-rows]
  data-dismissed:grid-rows-[0fr]">
  <div class="overflow-hidden">…promo…</div>

The row track animates from 1fr to 0fr and the inner element's overflow is clipped, so any content height collapses smoothly.

Dismissal persists. The script writes one key and reads it before paint, so a returning visitor never sees the strip flash in and out.

Three layers, one flow. Nothing is absolutely positioned: the strip, the utility row and the nav are stacked in normal flow, so collapsing the first simply lifts the rest.

Make it yours

  • Campaign colour: --color-tnb19-promo in @theme.
  • Collapse speed: duration-300 on the grid transition; past 500ms the header feels loose.
  • Session-only dismissal: swap localStorage for sessionStorage in the script.
  • Sticky main nav only: move sticky top-0 from the header to the nav row.

Gotchas — read before shipping

  • The 0fr collapse needs overflow-hidden on the inner element; without it the content stays visible at zero height.
  • Long promo copy wraps and pushes the whole header down — cap it with line-clamp-1 or shorten the message.
  • Reading localStorage after first paint causes a visible flash; set the attribute in the same synchronous script that renders.
  • Dismissal must not be the only way to reach the promo's offer — keep the link elsewhere too.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Animatable grid-template-rows landed in Chrome 107, Safari 16 and Firefox 66; inside Tailwind v4's floor.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Theme tokensset in @theme, used by a utility

Search CodeFronts

Loading…