Open demo

CSS code

HTML
<header class="cg">
  <a class="cg-logo" href="#">Kestrel</a>
  <button class="cg-toggle" type="button" aria-expanded="false" aria-controls="cg-menu" aria-label="Menu" data-menu-button><i></i><i></i><i></i></button>
  <nav class="cg-menu" id="cg-menu" aria-label="Main">
    <ul>
      <li><a href="#" aria-current="page">Product</a></li>
      <li><a href="#">Docs</a></li>
      <li><a href="#">Pricing</a></li>
    </ul>
  </nav>
  <div class="cg-actions"><a class="cg-ghost" href="#">Sign in</a><a class="cg-primary" href="#">Start free</a></div>
</header>
CSS
/* Dual-CTA header: a quiet text link beside a filled primary button, so the primary reads as the default.
   Below 992px the links fold behind a menu button while both actions stay in the bar. */
.cg{position:sticky;top:0;z-index:10;display:flex;flex-wrap:wrap;align-items:center;min-height:70px;padding:0 34px;
  background:#fff;border-bottom:1px solid #ecedf2;color:#1a1d26}
.cg,.cg *{box-sizing:border-box}
.cg a{text-decoration:none}
.cg ul{list-style:none;margin:0;padding:0}
.cg a:focus-visible,.cg button:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.cg-logo{margin-right:32px;font-weight:800;font-size:1.06rem;color:#1a1d26}
.cg-menu ul{display:flex;gap:3px}
.cg-menu a{display:block;padding:9px 13px;font-size:.9rem;font-weight:600;color:#4b5468;border-radius:8px}
.cg-menu a:hover,.cg-menu a[aria-current="page"]{background:#f4f5f9;color:#1a1d26}
.cg-actions{display:flex;align-items:center;gap:9px;margin-left:auto}
.cg-ghost{font-size:.88rem;font-weight:600;color:#4b5468;padding:9px 15px;border-radius:9px}
.cg-ghost:hover{background:#f4f5f9;color:#1a1d26}
.cg-primary{font-size:.88rem;font-weight:700;padding:10px 19px;border-radius:10px;background:#4f46e5;color:#fff;
  box-shadow:0 6px 16px -8px rgba(79,70,229,.8);transition:transform .15s,box-shadow .15s}
.cg-primary:hover{transform:translateY(-1px);box-shadow:0 10px 22px -8px rgba(79,70,229,.9)}
.cg-toggle{display:none;flex:none;width:44px;height:44px;flex-direction:column;align-items:center;justify-content:center;
  gap:5px;padding:0;background:#fff;border:1px solid #d9dfe8;border-radius:10px;cursor:pointer}
.cg-toggle i{display:block;width:20px;height:2px;border-radius:2px;background:#1a1d26;transition:transform .2s,opacity .2s}
.cg-toggle[aria-expanded="true"] i:nth-child(1){transform:translateY(7px) rotate(45deg)}
.cg-toggle[aria-expanded="true"] i:nth-child(2){opacity:0}
.cg-toggle[aria-expanded="true"] i:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
@media (max-width:991.98px){
  .cg{min-height:0;padding:10px 16px}
  .cg-logo{margin-right:12px}
  .cg-actions{order:1;gap:4px}
  .cg-ghost{padding:9px 10px}
  .cg-primary{padding:10px 14px}
  .cg-toggle{display:flex;order:2;margin-left:8px}
  .cg-menu{order:3;display:none;flex-basis:100%;padding:6px 0 12px;border-top:1px solid #ecedf2}
  .cg-menu[data-open]{display:block}
  .cg-menu ul{flex-direction:column}
  .cg-menu a{padding:11px 12px}
}
@media (prefers-reduced-motion:reduce){.cg *{transition:none!important}.cg-primary:hover{transform:none}}
JavaScript
/* Menu button: toggles aria-expanded on itself and data-open on the menu it controls (aria-controls).
   Esc closes an open menu and returns focus to the button; widening past 992px resets it. */
document.querySelectorAll('[data-menu-button]').forEach(btn => {
  const menu = document.getElementById(btn.getAttribute('aria-controls'));
  if (!menu) return;
  const set = open => { btn.setAttribute('aria-expanded', String(open)); menu.toggleAttribute('data-open', open); };
  btn.addEventListener('click', () => set(btn.getAttribute('aria-expanded') !== 'true'));
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape' && btn.getAttribute('aria-expanded') === 'true') { set(false); btn.focus(); }
  });
  matchMedia('(min-width: 992px)').addEventListener('change', e => { if (e.matches) set(false); });
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS, Bootstrap 5.3.8 JS bundle

HTML
<header class="navbar navbar-expand-lg cg">
  <a class="navbar-brand cg-logo" href="#">Kestrel</a>
  <button class="navbar-toggler cg-toggle order-2 order-lg-0 ms-2 ms-lg-0" type="button" data-bs-toggle="collapse" data-bs-target="#cg-menu" aria-controls="cg-menu" aria-expanded="false" aria-label="Menu"><i></i><i></i><i></i></button>
  <nav class="collapse navbar-collapse order-3 order-lg-0" id="cg-menu" aria-label="Main">
    <ul class="navbar-nav">
      <li class="nav-item"><a class="nav-link active" href="#" aria-current="page">Product</a></li>
      <li class="nav-item"><a class="nav-link" href="#">Docs</a></li>
      <li class="nav-item"><a class="nav-link" href="#">Pricing</a></li>
    </ul>
  </nav>
  <div class="cg-actions d-flex align-items-center order-1 order-lg-0 ms-auto"><a class="btn cg-ghost" href="#">Sign in</a><a class="btn cg-primary" href="#">Start free</a></div>
</header>
CSS
/* Bootstrap .navbar-expand-lg with two .btn actions restyled through --bs-btn-* variables. Order utilities keep
   the actions in the bar beside the toggler below 992px, while the links fold into .navbar-collapse. */
.cg{--bs-navbar-padding-x:34px;--bs-navbar-padding-y:0;--bs-navbar-color:#4b5468;--bs-navbar-hover-color:#1a1d26;
  --bs-navbar-active-color:#1a1d26;--bs-navbar-brand-color:#1a1d26;--bs-navbar-brand-hover-color:#1a1d26;
  --bs-navbar-brand-padding-y:0;--bs-navbar-brand-margin-end:32px;--bs-navbar-brand-font-size:1.06rem;--bs-navbar-nav-link-padding-x:13px;
  position:sticky;top:0;z-index:10;min-height:70px;background:#fff;border-bottom:1px solid #ecedf2}
.cg a:focus-visible,.cg button:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.cg-logo{font-weight:800}
.cg .navbar-nav{--bs-nav-link-padding-y:9px;--bs-nav-link-font-size:.9rem;--bs-nav-link-font-weight:600;gap:3px}
.cg .nav-link{border-radius:8px}
.cg .nav-link:hover,.cg .nav-link.active{background:#f4f5f9}
.cg .nav-link:focus-visible{box-shadow:none}
.cg-actions{gap:9px}
.cg .btn{--bs-btn-font-size:.88rem;--bs-btn-line-height:normal;--bs-btn-border-width:0}
.cg-ghost{--bs-btn-font-weight:600;--bs-btn-color:#4b5468;--bs-btn-hover-color:#1a1d26;--bs-btn-hover-bg:#f4f5f9;
  --bs-btn-active-color:#1a1d26;--bs-btn-active-bg:#f4f5f9;--bs-btn-padding-x:15px;--bs-btn-padding-y:9px;--bs-btn-border-radius:9px;
  --bs-btn-focus-box-shadow:none}
.cg-primary{--bs-btn-font-weight:700;--bs-btn-color:#fff;--bs-btn-bg:#4f46e5;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#4f46e5;
  --bs-btn-active-color:#fff;--bs-btn-active-bg:#4338ca;--bs-btn-padding-x:19px;--bs-btn-padding-y:10px;--bs-btn-border-radius:10px;
  --bs-btn-focus-box-shadow:0 6px 16px -8px rgba(79,70,229,.8);
  box-shadow:0 6px 16px -8px rgba(79,70,229,.8);transition:transform .15s,box-shadow .15s}
.cg-primary:hover{transform:translateY(-1px);box-shadow:0 10px 22px -8px rgba(79,70,229,.9)}
.cg .navbar-toggler{width:44px;height:44px;padding:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:5px;background:#fff;border:1px solid #d9dfe8;border-radius:10px}
.cg .navbar-toggler:focus{box-shadow:none}
.cg .navbar-toggler i{display:block;width:20px;height:2px;border-radius:2px;background:#1a1d26;transition:transform .2s,opacity .2s}
.cg .navbar-toggler[aria-expanded="true"] i:nth-child(1){transform:translateY(7px) rotate(45deg)}
.cg .navbar-toggler[aria-expanded="true"] i:nth-child(2){opacity:0}
.cg .navbar-toggler[aria-expanded="true"] i:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
@media (min-width:992px){.cg .navbar-toggler{display:none}}
@media (max-width:991.98px){
  .cg{--bs-navbar-padding-x:16px;--bs-navbar-padding-y:10px;--bs-navbar-brand-margin-end:12px;min-height:0;flex-wrap:wrap;justify-content:flex-start}
  .cg-actions{gap:4px}
  .cg-ghost{--bs-btn-padding-x:10px}
  .cg-primary{--bs-btn-padding-x:14px}
  .cg .navbar-nav{--bs-nav-link-padding-x:12px;--bs-nav-link-padding-y:11px;padding:6px 0 12px;border-top:1px solid #ecedf2}
}
@media (prefers-reduced-motion:reduce){.cg *{transition:none!important}.cg-primary:hover{transform:none}}
JavaScript
/* Bootstrap's Collapse has no Esc handling of its own: close an open navbar menu on Esc
   and return focus to its toggler. */
document.addEventListener('keydown', e => {
  if (e.key !== 'Escape') return;
  document.querySelectorAll('.navbar-collapse.show').forEach(menu => {
    bootstrap.Collapse.getOrCreateInstance(menu, { toggle: false }).hide();
    document.querySelector(`[data-bs-target="#${menu.id}"]`)?.focus();
  });
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<header class="sticky top-0 z-10 flex min-h-[70px] flex-wrap items-center border-b border-[#ecedf2] bg-white px-[34px] text-[#1a1d26] max-lg:min-h-0 max-lg:px-4 max-lg:py-2.5">
  <a class="mr-8 text-[1.06rem] font-extrabold text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] max-lg:mr-3" href="#">Kestrel</a>
  <button class="group flex size-11 flex-none cursor-pointer flex-col items-center justify-center gap-[5px] rounded-[10px] border border-[#d9dfe8] bg-white p-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] lg:hidden max-lg:order-2 max-lg:ml-2" type="button" aria-expanded="false" aria-controls="cg-menu" aria-label="Menu" data-menu-button><i class="block h-0.5 w-5 rounded-sm bg-[#1a1d26] transition-transform duration-200 motion-reduce:transition-none group-aria-expanded:translate-y-[7px] group-aria-expanded:rotate-45"></i><i class="block h-0.5 w-5 rounded-sm bg-[#1a1d26] transition-opacity duration-200 motion-reduce:transition-none group-aria-expanded:opacity-0"></i><i class="block h-0.5 w-5 rounded-sm bg-[#1a1d26] transition-transform duration-200 motion-reduce:transition-none group-aria-expanded:-translate-y-[7px] group-aria-expanded:-rotate-45"></i></button>
  <nav class="hidden data-open:block lg:block max-lg:order-3 max-lg:basis-full max-lg:border-t max-lg:border-[#ecedf2] max-lg:pt-1.5 max-lg:pb-3" id="cg-menu" aria-label="Main">
    <ul class="flex gap-[3px] max-lg:flex-col">
      <li><a class="block rounded-lg px-[13px] py-[9px] text-[.9rem] font-semibold text-[#4b5468] hover:bg-[#f4f5f9] hover:text-[#1a1d26] aria-[current=page]:bg-[#f4f5f9] aria-[current=page]:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] max-lg:px-3 max-lg:py-[11px]" href="#" aria-current="page">Product</a></li>
      <li><a class="block rounded-lg px-[13px] py-[9px] text-[.9rem] font-semibold text-[#4b5468] hover:bg-[#f4f5f9] hover:text-[#1a1d26] aria-[current=page]:bg-[#f4f5f9] aria-[current=page]:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] max-lg:px-3 max-lg:py-[11px]" href="#">Docs</a></li>
      <li><a class="block rounded-lg px-[13px] py-[9px] text-[.9rem] font-semibold text-[#4b5468] hover:bg-[#f4f5f9] hover:text-[#1a1d26] aria-[current=page]:bg-[#f4f5f9] aria-[current=page]:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] max-lg:px-3 max-lg:py-[11px]" href="#">Pricing</a></li>
    </ul>
  </nav>
  <div class="ml-auto flex items-center gap-[9px] max-lg:order-1 max-lg:gap-1">
    <a class="rounded-[9px] px-[15px] py-[9px] text-[.88rem] font-semibold text-[#4b5468] hover:bg-[#f4f5f9] hover:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] max-lg:px-2.5" href="#">Sign in</a>
    <a class="rounded-[10px] bg-[#4f46e5] px-[19px] py-2.5 text-[.88rem] font-bold text-white shadow-[0_6px_16px_-8px_rgba(79,70,229,.8)] transition-[transform,box-shadow] duration-150 hover:-translate-y-px hover:shadow-[0_10px_22px_-8px_rgba(79,70,229,.9)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none motion-reduce:hover:translate-y-0 max-lg:px-3.5" href="#">Start free</a>
  </div>
</header>
CSS
@theme {
  --breakpoint-lg: 62rem; /* 992px, the same collapse point as Bootstrap's navbar-expand-lg */
}
JavaScript
/* Menu button: toggles aria-expanded on itself and data-open on the menu it controls (aria-controls).
   Esc closes an open menu and returns focus to the button; widening past 992px resets it. */
document.querySelectorAll('[data-menu-button]').forEach(btn => {
  const menu = document.getElementById(btn.getAttribute('aria-controls'));
  if (!menu) return;
  const set = open => { btn.setAttribute('aria-expanded', String(open)); menu.toggleAttribute('data-open', open); };
  btn.addEventListener('click', () => set(btn.getAttribute('aria-expanded') !== 'true'));
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape' && btn.getAttribute('aria-expanded') === 'true') { set(false); btn.focus(); }
  });
  matchMedia('(min-width: 992px)').addEventListener('change', e => { if (e.matches) set(false); });
});

About this set

A SaaS header with two actions of clearly different weight: a quiet “Sign in” text link beside a filled indigo “Start free” button with a tinted shadow. Two buttons of equal weight make people choose twice; giving the secondary action no fill is what makes the primary read as the default. The logo and three links (Product, Docs, Pricing) sit on the left and the actions on the right, and the bar is sticky. Use it for a product site where sign-ups matter more than browsing. Below 992px the links fold behind a menu button, but both actions stay in the bar next to it, so the primary action is never hidden in a menu. The layout is one flex row that wraps: order moves the actions before the menu button on narrow screens, and the menu takes a full-width row underneath. In Bootstrap the actions are .btn elements restyled through –bs-btn-* variables and positioned with order utilities.

What’s included

  • Ghost secondary action beside a filled primary button
  • Both actions stay visible beside the menu button on phones
  • Current page styled from aria-current="page"
  • Primary button lift switches off under reduced motion
  • Bootstrap .btn variants built from --bs-btn-* variables

Accessibility

The links sit in a nav labelled Main with aria-current="page" on the current one. The menu button is a real button with an accessible name that reports aria-expanded; it opens with Enter or Space, and Esc closes the menu and returns focus to the button. Every link and button shows a 2px indigo outline on keyboard focus, and the hover lift and transitions switch off under prefers-reduced-motion.

Customise it

Change #4f46e5 on .cg-primary (and its rgba shadow) for the brand colour, and #f4f5f9 for the hover and current-link fill. In Bootstrap set --bs-btn-bg and --bs-btn-hover-bg on .cg-primary; in Tailwind edit bg-[#4f46e5] and the shadow-[…] utilities.