Open demo

CSS code

HTML
<header class="ap">
  <span class="ap-logo" aria-hidden="true">N</span>
  <a class="ap-ws" href="#">Northwind <em>· Production</em></a>
  <button class="ap-toggle" type="button" aria-expanded="false" aria-controls="ap-menu" aria-label="Menu" data-menu-button><i></i><i></i><i></i></button>
  <nav class="ap-menu" id="ap-menu" aria-label="Main">
    <ul>
      <li><a href="#" aria-current="page">Overview</a></li>
      <li><a href="#">Deployments</a></li>
      <li><a href="#">Settings</a></li>
    </ul>
  </nav>
  <div class="ap-tools">
    <a class="ap-icon" href="#" aria-label="Search"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></a>
    <a class="ap-icon" href="#" aria-label="Notifications, new activity"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span class="ap-dot"></span></a>
    <a class="ap-avatar" href="#" aria-label="Your account">AL</a>
  </div>
</header>
CSS
/* Application header: logo mark, workspace switcher and section tabs on the left, icon controls on the right.
   Every icon-only control has an aria-label. Below 992px the section tabs fold behind a menu button. */
.ap{position:sticky;top:0;z-index:10;display:flex;flex-wrap:wrap;align-items:center;column-gap:16px;min-height:58px;
  padding:0 18px;background:#fff;border-bottom:1px solid #e8eaf0;color:#1a1d26}
.ap,.ap *{box-sizing:border-box}
.ap a{text-decoration:none}
.ap ul{list-style:none;margin:0;padding:0}
.ap a:focus-visible,.ap button:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.ap-logo{flex:none;width:30px;height:30px;border-radius:9px;background:#4f46e5;display:grid;place-items:center;
  color:#fff;font-weight:800;font-size:.85rem}
.ap-ws{display:flex;align-items:center;gap:8px;padding:6px 11px;border-radius:9px;font-size:.87rem;font-weight:600;
  color:#1a1d26;border:1px solid #e8eaf0;white-space:nowrap}
.ap-ws:hover{background:#f5f6fa}
.ap-ws em{font-style:normal;color:#6b7385;font-size:.78rem}
.ap-menu ul{display:flex;gap:2px}
.ap-menu a{display:flex;align-items:center;height:58px;padding:0 10px;font-size:.87rem;font-weight:600;color:#4b5468;
  box-shadow:inset 0 -2px transparent}
.ap-menu a:hover{color:#1a1d26}
.ap-menu a:focus-visible{outline-offset:-2px}
.ap-menu a[aria-current="page"]{color:#1a1d26;box-shadow:inset 0 -2px #4f46e5}
.ap-tools{display:flex;align-items:center;gap:4px;margin-left:auto}
.ap-icon{position:relative;width:34px;height:34px;border-radius:9px;display:grid;place-items:center;color:#6b7385}
.ap-icon:hover{background:#f3f4f9;color:#1a1d26}
.ap-dot{position:absolute;top:6px;right:7px;width:11px;height:11px;border-radius:50%;background:#ef4444;border:2px solid #fff}
.ap-avatar{width:32px;height:32px;margin-left:6px;border-radius:50%;background:#0369a1;color:#fff;display:grid;
  place-items:center;font-weight:700;font-size:.8rem}
.ap-toggle{display:none;flex:none;width:36px;height:36px;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;padding:0;background:#fff;border:0;border-radius:9px;cursor:pointer}
.ap-toggle i{display:block;width:18px;height:2px;border-radius:2px;background:#4b5468;transition:transform .2s,opacity .2s}
.ap-toggle[aria-expanded="true"] i:nth-child(1){transform:translateY(6px) rotate(45deg)}
.ap-toggle[aria-expanded="true"] i:nth-child(2){opacity:0}
.ap-toggle[aria-expanded="true"] i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
.ap-toggle:hover{background:#f3f4f9}
@media (max-width:991.98px){
  .ap{column-gap:8px;min-height:0;padding:11px 12px}
  .ap-ws em{display:none}
  .ap-tools{order:1}
  .ap-toggle{display:flex;order:2}
  .ap-menu{order:3;display:none;flex-basis:100%;padding:4px 0 10px;border-top:1px solid #e8eaf0}
  .ap-menu[data-open]{display:block}
  .ap-menu ul{flex-direction:column}
  .ap-menu a{height:auto;padding:11px 10px;border-radius:8px;box-shadow:none}
  .ap-menu a[aria-current="page"]{background:#eef2ff;color:#4338ca;box-shadow:none}
}
@media (prefers-reduced-motion:reduce){.ap *{transition:none!important}}
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 ap">
  <span class="ap-logo" aria-hidden="true">N</span>
  <a class="ap-ws" href="#">Northwind <em>· Production</em></a>
  <button class="navbar-toggler ap-toggle order-2 order-lg-0" type="button" data-bs-toggle="collapse" data-bs-target="#ap-menu" aria-controls="ap-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="ap-menu" aria-label="Main">
    <ul class="navbar-nav">
      <li class="nav-item"><a class="nav-link active" href="#" aria-current="page">Overview</a></li>
      <li class="nav-item"><a class="nav-link" href="#">Deployments</a></li>
      <li class="nav-item"><a class="nav-link" href="#">Settings</a></li>
    </ul>
  </nav>
  <div class="ap-tools d-flex align-items-center order-1 order-lg-0 ms-auto">
    <a class="ap-icon" href="#" aria-label="Search"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></a>
    <a class="ap-icon" href="#" aria-label="Notifications, new activity"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span class="ap-dot"></span></a>
    <a class="ap-avatar rounded-circle" href="#" aria-label="Your account">AL</a>
  </div>
</header>
CSS
/* Bootstrap .navbar-expand-lg for an app bar: the section links are .nav-link tabs from 992px and fold into the
   collapse below it, while order utilities keep the icon controls in the bar beside the toggler. */
.ap{--bs-navbar-padding-x:18px;--bs-navbar-padding-y:0;--bs-navbar-color:#4b5468;--bs-navbar-hover-color:#1a1d26;
  --bs-navbar-active-color:#1a1d26;--bs-navbar-nav-link-padding-x:10px;
  position:sticky;top:0;z-index:10;column-gap:16px;min-height:58px;background:#fff;border-bottom:1px solid #e8eaf0}
.ap a{text-decoration:none}
.ap a:focus-visible,.ap button:focus-visible{outline:2px solid #4f46e5;outline-offset:2px;box-shadow:none}
.ap-logo{flex:none;width:30px;height:30px;border-radius:9px;background:#4f46e5;display:grid;place-items:center;
  color:#fff;font-weight:800;font-size:.85rem}
.ap-ws{display:flex;align-items:center;gap:8px;padding:6px 11px;border-radius:9px;font-size:.87rem;font-weight:600;
  color:#1a1d26;border:1px solid #e8eaf0;white-space:nowrap}
.ap-ws:hover{background:#f5f6fa;color:#1a1d26}
.ap-ws em{font-style:normal;color:#6b7385;font-size:.78rem}
.ap .navbar-nav{--bs-nav-link-font-size:.87rem;--bs-nav-link-font-weight:600;gap:2px}
.ap .nav-link{box-shadow:inset 0 -2px transparent}
.ap .nav-link.active{box-shadow:inset 0 -2px #4f46e5}
.ap .nav-link:focus-visible{outline-offset:-2px}
.ap-tools{gap:4px}
.ap-icon{position:relative;width:34px;height:34px;border-radius:9px;display:grid;place-items:center;color:#6b7385}
.ap-icon:hover{background:#f3f4f9;color:#1a1d26}
.ap-dot{position:absolute;top:6px;right:7px;width:11px;height:11px;border-radius:50%;background:#ef4444;border:2px solid #fff}
.ap-avatar{width:32px;height:32px;margin-left:6px;background:#0369a1;color:#fff;display:grid;place-items:center;font-weight:700;font-size:.8rem}
.ap-avatar:hover{color:#fff}
.ap .navbar-toggler{width:36px;height:36px;padding:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;background:#fff;border:0;border-radius:9px}
.ap .navbar-toggler:focus{box-shadow:none}
.ap .navbar-toggler i{display:block;width:18px;height:2px;border-radius:2px;background:#4b5468;transition:transform .2s,opacity .2s}
.ap .navbar-toggler[aria-expanded="true"] i:nth-child(1){transform:translateY(6px) rotate(45deg)}
.ap .navbar-toggler[aria-expanded="true"] i:nth-child(2){opacity:0}
.ap .navbar-toggler[aria-expanded="true"] i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
@media (min-width:992px){.ap .navbar-toggler{display:none}}
.ap .navbar-toggler:hover{background:#f3f4f9}
@media (min-width:992px){
  .ap .nav-link{display:flex;align-items:center;height:58px;padding-top:0;padding-bottom:0}
}
@media (max-width:991.98px){
  .ap{--bs-navbar-padding-x:12px;--bs-navbar-padding-y:11px;column-gap:8px;min-height:0;justify-content:flex-start}
  .ap-ws em{display:none}
  .ap .navbar-nav{--bs-nav-link-padding-x:10px;--bs-nav-link-padding-y:11px;padding:4px 0 10px;border-top:1px solid #e8eaf0}
  .ap .nav-link{border-radius:8px}
  .ap .nav-link.active{background:#eef2ff;color:#4338ca;box-shadow:none}
}
@media (prefers-reduced-motion:reduce){.ap *{transition:none!important}}
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-[58px] flex-wrap items-center gap-x-4 border-b border-[#e8eaf0] bg-white px-[18px] text-[#1a1d26] max-lg:min-h-0 max-lg:gap-x-2 max-lg:px-3 max-lg:py-[11px]">
  <span class="grid size-[30px] flex-none place-items-center rounded-[9px] bg-[#4f46e5] text-[.85rem] font-extrabold text-white" aria-hidden="true">N</span>
  <a class="flex items-center gap-2 rounded-[9px] border border-[#e8eaf0] px-[11px] py-1.5 text-[.87rem] font-semibold whitespace-nowrap text-[#1a1d26] hover:bg-[#f5f6fa] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]" href="#">Northwind <em class="text-[.78rem] text-[#6b7385] not-italic max-lg:hidden">· Production</em></a>
  <button class="group flex size-9 flex-none cursor-pointer flex-col items-center justify-center gap-1 rounded-[9px] border-0 bg-white p-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] lg:hidden hover:bg-[#f3f4f9] max-lg:order-2" type="button" aria-expanded="false" aria-controls="ap-menu" aria-label="Menu" data-menu-button><i class="block h-0.5 w-[18px] rounded-sm bg-[#4b5468] transition-transform duration-200 motion-reduce:transition-none group-aria-expanded:translate-y-[6px] group-aria-expanded:rotate-45"></i><i class="block h-0.5 w-[18px] rounded-sm bg-[#4b5468] transition-opacity duration-200 motion-reduce:transition-none group-aria-expanded:opacity-0"></i><i class="block h-0.5 w-[18px] rounded-sm bg-[#4b5468] transition-transform duration-200 motion-reduce:transition-none group-aria-expanded:-translate-y-[6px] 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-[#e8eaf0] max-lg:pt-1 max-lg:pb-2.5" id="ap-menu" aria-label="Main">
    <ul class="flex gap-0.5 max-lg:flex-col">
      <li><a class="flex h-[58px] items-center px-2.5 text-[.87rem] font-semibold text-[#4b5468] shadow-[inset_0_-2px_transparent] hover:text-[#1a1d26] aria-[current=page]:text-[#1a1d26] aria-[current=page]:shadow-[inset_0_-2px_#4f46e5] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] focus-visible:-outline-offset-2 max-lg:h-auto max-lg:rounded-lg max-lg:py-[11px] max-lg:shadow-none max-lg:aria-[current=page]:bg-[#eef2ff] max-lg:aria-[current=page]:text-[#4338ca] max-lg:aria-[current=page]:shadow-none" href="#" aria-current="page">Overview</a></li>
      <li><a class="flex h-[58px] items-center px-2.5 text-[.87rem] font-semibold text-[#4b5468] shadow-[inset_0_-2px_transparent] hover:text-[#1a1d26] aria-[current=page]:text-[#1a1d26] aria-[current=page]:shadow-[inset_0_-2px_#4f46e5] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] focus-visible:-outline-offset-2 max-lg:h-auto max-lg:rounded-lg max-lg:py-[11px] max-lg:shadow-none max-lg:aria-[current=page]:bg-[#eef2ff] max-lg:aria-[current=page]:text-[#4338ca] max-lg:aria-[current=page]:shadow-none" href="#">Deployments</a></li>
      <li><a class="flex h-[58px] items-center px-2.5 text-[.87rem] font-semibold text-[#4b5468] shadow-[inset_0_-2px_transparent] hover:text-[#1a1d26] aria-[current=page]:text-[#1a1d26] aria-[current=page]:shadow-[inset_0_-2px_#4f46e5] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] focus-visible:-outline-offset-2 max-lg:h-auto max-lg:rounded-lg max-lg:py-[11px] max-lg:shadow-none max-lg:aria-[current=page]:bg-[#eef2ff] max-lg:aria-[current=page]:text-[#4338ca] max-lg:aria-[current=page]:shadow-none" href="#">Settings</a></li>
    </ul>
  </nav>
  <div class="ml-auto flex items-center gap-1 max-lg:order-1">
    <a class="relative grid size-[34px] place-items-center rounded-[9px] text-[#6b7385] hover:bg-[#f3f4f9] hover:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]" href="#" aria-label="Search"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></a>
    <a class="relative grid size-[34px] place-items-center rounded-[9px] text-[#6b7385] hover:bg-[#f3f4f9] hover:text-[#1a1d26] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]" href="#" aria-label="Notifications, new activity"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span class="absolute top-1.5 right-[7px] size-[11px] rounded-full border-2 border-white bg-[#ef4444]"></span></a>
    <a class="ml-1.5 grid size-8 place-items-center rounded-full bg-[#0369a1] text-[.8rem] font-bold text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]" href="#" aria-label="Your account">AL</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

The compact 58px bar a signed-in product needs: a logo square, a workspace switcher (“Northwind · Production”), three section tabs (Overview, Deployments, Settings) with an indigo underline on the current one, and search, notification and account controls on the right. Use it for a dashboard, an admin panel or any web app. Every icon-only control has an aria-label (Search, “Notifications, new activity”, Your account), and the SVG icons are hidden from assistive technology; without the labels they would be announced as “link” and nothing else, which is the most common failure in an app header. The red dot on the bell is decoration, and the label says the same thing in words. Below 992px the environment name hides, the tabs fold behind a menu button, and the icon controls stay in the bar. The Bootstrap version places them with order utilities around .navbar-collapse.

What’s included

  • Workspace switcher, section tabs and icon controls in one bar
  • aria-label on every icon-only control; SVG icons aria-hidden
  • Current tab underlined from aria-current="page"
  • Tabs fold behind a menu button while the icons stay visible
  • Bootstrap .nav-link tabs with order utilities

Accessibility

Search, notifications and account each have an aria-label, and their SVG icons are aria-hidden. The tabs 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 control shows a 2px indigo outline on keyboard focus.

Customise it

Change #4f46e5 on .ap-logo and the current-tab underline, #0369a1 for the avatar and #ef4444 for the notification dot. In Bootstrap the tab colours are the --bs-navbar-* variables on .ap; in Tailwind edit the bg-[…] and shadow-[inset_…] utilities.