Open demo

CSS code

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="i-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5 12 4l8 6.5V19a1 1 0 0 1-1 1h-4.5v-6h-5v6H5a1 1 0 0 1-1-1z"/></symbol>
  <symbol id="i-chart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16M8 16v-5M12 16V8M16 16v-3"/></symbol>
  <symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8.5" r="3.5"/><path d="M2.5 20c.6-3.6 3.2-5.5 6.5-5.5s5.9 1.9 6.5 5.5"/><path d="M16 5.2a3.3 3.3 0 0 1 0 6.6M18 14.8c2 .6 3.2 2.3 3.5 5.2"/></symbol>
  <symbol id="i-card" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5.5" width="18" height="13" rx="2.5"/><path d="M3 10h18M7 15h3"/></symbol>
  <symbol id="i-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 3v2.5M12 18.5V21M3 12h2.5M18.5 12H21M5.6 5.6l1.8 1.8M16.6 16.6l1.8 1.8M5.6 18.4l1.8-1.8M16.6 7.4l1.8-1.8"/></symbol>
  <symbol id="i-rocket" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15.5 8.5 12C10 7 13.5 4 19.5 4.5 20 10.5 17 14 12 15.5z"/><path d="M8.5 12 5 11.5 7.5 8.5h3.5M12 15.5l.5 3.5 3-2.5V13"/><circle cx="15" cy="9" r="1.2"/></symbol>
</svg>

<div><span class="lbl">Icon rail labels</span>
<div class="stage" style="--stage-h:330px">
  <nav aria-label="Main">
    <ul class="rail">
      <li><span class="tt"><a href="#overview" aria-labelledby="rl-1"><svg aria-hidden="true"><use href="#i-home"/></svg></a><span class="tt-tip tt-right" role="tooltip" id="rl-1">Overview</span></span></li>
      <li><span class="tt" id="tt-rail"><a href="#analytics" aria-current="page" aria-labelledby="rl-2"><svg aria-hidden="true"><use href="#i-chart"/></svg></a><span class="tt-tip tt-right" role="tooltip" id="rl-2">Analytics</span></span></li>
      <li><span class="tt"><a href="#customers" aria-labelledby="rl-3"><svg aria-hidden="true"><use href="#i-users"/></svg></a><span class="tt-tip tt-right" role="tooltip" id="rl-3">Customers</span></span></li>
      <li><span class="tt"><a href="#billing" aria-labelledby="rl-4"><svg aria-hidden="true"><use href="#i-card"/></svg></a><span class="tt-tip tt-right" role="tooltip" id="rl-4">Billing</span></span></li>
      <li><span class="tt"><a href="#settings" aria-labelledby="rl-5"><svg aria-hidden="true"><use href="#i-gear"/></svg></a><span class="tt-tip tt-right" role="tooltip" id="rl-5">Settings</span></span></li>
    </ul>
  </nav>
</div></div>

<div><span class="lbl">Values on a chart</span>
<div class="stage" style="--stage-h:330px">
  <ul class="chart" aria-label="Sessions per day, 13 to 19 October">
    <li><span class="tt" style="--h:46%"><span class="bar" tabindex="0" role="img" aria-label="Monday 13 October: 1,062 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Mon 13 Oct</b><small>1,062 sessions</small></span></span></li>
    <li><span class="tt" style="--h:58%"><span class="bar" tabindex="0" role="img" aria-label="Tuesday 14 October: 1,284 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Tue 14 Oct</b><small>1,284 sessions</small></span></span></li>
    <li><span class="tt" style="--h:64%"><span class="bar" tabindex="0" role="img" aria-label="Wednesday 15 October: 1,410 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Wed 15 Oct</b><small>1,410 sessions</small></span></span></li>
    <li><span class="tt" id="tt-bar" style="--h:88%"><span class="bar" tabindex="0" role="img" aria-label="Thursday 16 October: 1,912 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Thu 16 Oct</b><small>1,912 sessions</small></span></span></li>
    <li><span class="tt" style="--h:70%"><span class="bar" tabindex="0" role="img" aria-label="Friday 17 October: 1,536 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Fri 17 Oct</b><small>1,536 sessions</small></span></span></li>
    <li><span class="tt" style="--h:33%"><span class="bar" tabindex="0" role="img" aria-label="Saturday 18 October: 731 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Sat 18 Oct</b><small>731 sessions</small></span></span></li>
    <li><span class="tt" style="--h:44%"><span class="bar" tabindex="0" role="img" aria-label="Sunday 19 October: 969 sessions"></span><span class="tt-tip tt-top tt-slate" aria-hidden="true"><b>Sun 19 Oct</b><small>969 sessions</small></span></span></li>
  </ul>
  <ul class="days" aria-hidden="true"><li>M</li><li>T</li><li>W</li><li>T</li><li>F</li><li>S</li><li>S</li></ul>
  <p class="sum">This week <b>8,904 sessions</b>, peak on Thursday.</p>
</div></div>

<div class="full"><span class="lbl">Glow accent</span>
<div class="stage">
  <div class="row">
    <span class="tt" id="tt-deploy"><button class="deploy" type="button" aria-describedby="tip-deploy"><svg aria-hidden="true"><use href="#i-rocket"/></svg>Deploy</button><span class="tt-tip tt-bottom tt-glow" role="tooltip" id="tip-deploy"><code>main</code> to production, 3 new commits</span></span>
    <span class="tt"><button class="live" type="button" aria-describedby="tip-live"><i aria-hidden="true"></i>214 online</button><span class="tt-tip tt-bottom tt-slate" role="tooltip" id="tip-live">People with the app open in the last 5 minutes</span></span>
  </div>
</div></div>
CSS
/* Dark-UI tooltips. On a near-black page a black tooltip disappears, so these are lighter than the page or outlined:
   filter: drop-shadow draws the outline around the bubble and its arrow together. */
.tt{--tt-gap:10px;--tt-arrow:6px;position:relative;display:inline-flex;vertical-align:middle}
.tt-tip{--tt-bg:#e2e8f0;--tt-ink:#0b1120;position:absolute;z-index:30;width:max-content;max-width:220px;padding:6px 10px;border-radius:8px;background:var(--tt-bg);color:var(--tt-ink);
  font:600 .8125rem/1.45 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;text-align:left;white-space:normal;
  filter:drop-shadow(0 10px 16px rgba(0,0,0,.45));visibility:hidden;opacity:0;scale:0;transition:opacity .15s,visibility .15s,scale 0s .15s}
.tt:is(:hover,:focus-within,.is-open):not(.is-dismissed)>.tt-tip{visibility:visible;opacity:1;scale:1;transition:opacity .15s,visibility 0s,scale 0s}
.tt-tip::before{content:"";position:absolute;border:var(--tt-arrow) solid transparent}
.tt-tip::after{content:"";position:absolute}
.tt-top{bottom:calc(100% + var(--tt-gap));left:50%;translate:calc(-50% + var(--tt-nudge,0px)) 0}
.tt-top::before{top:100%;left:calc(50% - var(--tt-arrow) - var(--tt-nudge,0px));border-top-color:var(--tt-bg);border-bottom-width:0}
.tt-top::after{top:100%;left:0;right:0;height:var(--tt-gap)}
.tt-bottom{top:calc(100% + var(--tt-gap));left:50%;translate:calc(-50% + var(--tt-nudge,0px)) 0}
.tt-bottom::before{bottom:100%;left:calc(50% - var(--tt-arrow) - var(--tt-nudge,0px));border-bottom-color:var(--tt-bg);border-top-width:0}
.tt-bottom::after{bottom:100%;left:0;right:0;height:var(--tt-gap)}
.tt-right{left:calc(100% + var(--tt-gap));top:50%;translate:0 -50%}
.tt-right::before{right:100%;top:calc(50% - var(--tt-arrow));border-right-color:var(--tt-bg);border-left-width:0}
.tt-right::after{right:100%;top:0;bottom:0;width:var(--tt-gap)}
/* Outlined slate tooltip and cyan glow */
.tt-slate{--tt-bg:#1e293b;--tt-ink:#f1f5f9;font-weight:500;filter:drop-shadow(0 0 .7px #64748b) drop-shadow(0 12px 18px rgba(0,0,0,.5))}
.tt-slate b{display:block;color:#fff;font-weight:650}
.tt-slate small{color:#cbd5e1;font-size:.75rem}
.tt-glow{--tt-bg:#082f3a;--tt-ink:#cffafe;max-width:270px;font-weight:500;filter:drop-shadow(0 0 .8px #22d3ee) drop-shadow(0 0 14px rgba(34,211,238,.4))}
.tt-glow code{color:#67e8f9;font:600 .75rem ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

/* Icon rail */
.rail{display:inline-flex;flex-direction:column;gap:6px;margin:0;padding:8px;border:1px solid #1f2a44;border-radius:16px;background:#0b1222;list-style:none}
.rail a{display:grid;place-items:center;width:42px;height:42px;border-radius:11px;color:#94a3b8;transition:background-color .15s,color .15s}
.rail a:hover{background:#18233a;color:#e2e8f0}
.rail a[aria-current="page"]{background:#12324a;color:#67e8f9}
.rail svg{width:20px;height:20px}
/* Bar chart */
.chart{display:flex;align-items:flex-end;gap:10px;height:200px;margin:0;padding:64px 0 0;list-style:none;border-bottom:1px solid #26324d}
.chart li{flex:1;display:flex;flex-direction:column;align-items:stretch;justify-content:flex-end;height:100%}
.chart .tt{display:flex;height:var(--h)}
.bar{flex:1;border-radius:6px 6px 2px 2px;background:linear-gradient(#22d3ee,#0e7490);opacity:.75;transition:opacity .15s}
.bar:hover,.tt.is-open .bar,.bar:focus-visible{opacity:1}
.days{display:flex;gap:10px;margin:8px 0 0;padding:0;list-style:none;color:#94a3b8;font-size:.75rem;text-align:center}
.days li{flex:1}
.sum{margin:14px 0 0;color:#cbd5e1;font-size:.8125rem}
.sum b{color:#fff}
/* Glow trigger */
.deploy{display:inline-flex;align-items:center;gap:8px;height:40px;padding:0 16px;border:1px solid #155e75;border-radius:10px;background:linear-gradient(#0e7490,#155e75);color:#ecfeff;
  font:600 .875rem/1 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;cursor:pointer;box-shadow:0 0 0 1px rgba(34,211,238,.15),0 8px 24px -8px rgba(34,211,238,.5)}
.deploy:hover{background:linear-gradient(#0891b2,#0e7490)}
.deploy svg{width:16px;height:16px}
.live{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 12px;border:1px solid #1f2a44;border-radius:999px;background:#0b1222;color:#e2e8f0;font:600 .8125rem/1 ui-sans-serif,system-ui,sans-serif;cursor:help}
.live i{width:8px;height:8px;border-radius:50%;background:#4ade80;box-shadow:0 0 0 3px rgba(74,222,128,.2)}
.row{display:flex;flex-wrap:wrap;align-items:center;gap:20px 28px;padding-bottom:58px}
:is(.rail a,.bar,.deploy,.live):focus-visible{outline:2px solid #67e8f9;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.tt .tt-tip,.tt:is(:hover,:focus-within,.is-open):not(.is-dismissed)>.tt-tip,.rail a,.bar{transition:none}}
JavaScript
// Tooltip behaviour for WCAG 1.4.13: Esc dismisses without moving focus or the pointer, a tap opens it on touch screens,
// opening one closes the others, and top/bottom tooltips are nudged sideways to stay inside the window.
(() => {
  const tts = [...document.querySelectorAll('.tt')];
  const fit = t => {
    const tip = t.querySelector(':scope > .tt-top, :scope > .tt-bottom'); if (!tip) return;
    tip.style.removeProperty('--tt-nudge');
    requestAnimationFrame(() => {
      const r = tip.getBoundingClientRect(), w = document.documentElement.clientWidth;
      const d = r.left < 8 ? 8 - r.left : r.right > w - 8 ? w - 8 - r.right : 0;
      if (d) tip.style.setProperty('--tt-nudge', d + 'px');
    });
  };
  const enter = t => { tts.forEach(o => o !== t && o.classList.remove('is-open')); t.classList.remove('is-dismissed'); fit(t); };
  tts.forEach(t => { t.addEventListener('pointerenter', () => enter(t)); t.addEventListener('focusin', () => enter(t)); if (t.classList.contains('is-open')) fit(t); });
  document.addEventListener('pointerdown', e => {
    const t = e.target.closest('.tt');
    if (!t) tts.forEach(o => o.classList.remove('is-open'));
    else if (e.pointerType === 'touch') t.classList.add('is-open');
  });
  document.addEventListener('keydown', e => {
    if (e.key !== 'Escape') return;
    tts.filter(t => t.matches(':hover, :focus-within, .is-open')).forEach(t => { t.classList.remove('is-open'); t.classList.add('is-dismissed'); });
  });
})();

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS, Bootstrap 5.3.8 JS bundle

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="i-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5 12 4l8 6.5V19a1 1 0 0 1-1 1h-4.5v-6h-5v6H5a1 1 0 0 1-1-1z"/></symbol>
  <symbol id="i-chart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16M8 16v-5M12 16V8M16 16v-3"/></symbol>
  <symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8.5" r="3.5"/><path d="M2.5 20c.6-3.6 3.2-5.5 6.5-5.5s5.9 1.9 6.5 5.5"/><path d="M16 5.2a3.3 3.3 0 0 1 0 6.6M18 14.8c2 .6 3.2 2.3 3.5 5.2"/></symbol>
  <symbol id="i-card" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5.5" width="18" height="13" rx="2.5"/><path d="M3 10h18M7 15h3"/></symbol>
  <symbol id="i-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 3v2.5M12 18.5V21M3 12h2.5M18.5 12H21M5.6 5.6l1.8 1.8M16.6 16.6l1.8 1.8M5.6 18.4l1.8-1.8M16.6 7.4l1.8-1.8"/></symbol>
  <symbol id="i-rocket" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15.5 8.5 12C10 7 13.5 4 19.5 4.5 20 10.5 17 14 12 15.5z"/><path d="M8.5 12 5 11.5 7.5 8.5h3.5M12 15.5l.5 3.5 3-2.5V13"/><circle cx="15" cy="9" r="1.2"/></symbol>
</svg>

<div><span class="lbl">Icon rail labels</span>
<div class="stage" style="--stage-h:330px">
  <nav class="nav flex-column d-inline-flex rail" aria-label="Main">
    <a class="nav-link" href="#overview" aria-label="Overview" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Overview" data-tt-label><svg aria-hidden="true"><use href="#i-home"/></svg></a>
    <a class="nav-link active" href="#analytics" id="tt-rail" aria-current="page" aria-label="Analytics" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Analytics" data-tt-label><svg aria-hidden="true"><use href="#i-chart"/></svg></a>
    <a class="nav-link" href="#customers" aria-label="Customers" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Customers" data-tt-label><svg aria-hidden="true"><use href="#i-users"/></svg></a>
    <a class="nav-link" href="#billing" aria-label="Billing" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Billing" data-tt-label><svg aria-hidden="true"><use href="#i-card"/></svg></a>
    <a class="nav-link" href="#settings" aria-label="Settings" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Settings" data-tt-label><svg aria-hidden="true"><use href="#i-gear"/></svg></a>
  </nav>
</div></div>

<div><span class="lbl">Values on a chart</span>
<div class="stage" style="--stage-h:330px">
  <ul class="chart" aria-label="Sessions per day, 13 to 19 October">
    <li><span class="bar" style="--h:46%" tabindex="0" role="img" aria-label="Monday 13 October: 1,062 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Mon 13 Oct</b><small>1,062 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:58%" tabindex="0" role="img" aria-label="Tuesday 14 October: 1,284 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Tue 14 Oct</b><small>1,284 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:64%" tabindex="0" role="img" aria-label="Wednesday 15 October: 1,410 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Wed 15 Oct</b><small>1,410 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:88%" id="tt-bar" tabindex="0" role="img" aria-label="Thursday 16 October: 1,912 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Thu 16 Oct</b><small>1,912 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:70%" tabindex="0" role="img" aria-label="Friday 17 October: 1,536 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Fri 17 Oct</b><small>1,536 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:33%" tabindex="0" role="img" aria-label="Saturday 18 October: 731 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Sat 18 Oct</b><small>731 sessions</small>" data-tt-label></span></li>
    <li><span class="bar" style="--h:44%" tabindex="0" role="img" aria-label="Sunday 19 October: 969 sessions" data-bs-toggle="tooltip" data-bs-custom-class="tt-slate" data-bs-html="true" data-bs-title="<b>Sun 19 Oct</b><small>969 sessions</small>" data-tt-label></span></li>
  </ul>
  <ul class="days" aria-hidden="true"><li>M</li><li>T</li><li>W</li><li>T</li><li>F</li><li>S</li><li>S</li></ul>
  <p class="mt-3 mb-0" style="color:#cbd5e1;font-size:.8125rem">This week <b class="text-white">8,904 sessions</b>, peak on Thursday.</p>
</div></div>

<div class="full"><span class="lbl">Glow accent</span>
<div class="stage">
  <div class="d-flex flex-wrap align-items-center" style="gap:20px 28px;padding-bottom:58px">
    <button class="btn deploy" type="button" id="tt-deploy" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-custom-class="tt-glow" data-bs-html="true" data-bs-title="<code>main</code> to production, 3 new commits"><svg aria-hidden="true"><use href="#i-rocket"/></svg>Deploy</button>
    <button class="live rounded-pill" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-custom-class="tt-slate" data-bs-title="People with the app open in the last 5 minutes"><i aria-hidden="true"></i>214 online</button>
  </div>
</div></div>
CSS
/* Bootstrap Tooltip in data-bs-theme="dark". On a near-black page a black tooltip disappears, so these are lighter than the page
   or outlined: filter: drop-shadow on .tooltip draws the outline around the bubble and its arrow together. */
.tooltip.tt{--bs-tooltip-bg:#e2e8f0;--bs-tooltip-color:#0b1120;--bs-tooltip-opacity:1;--bs-tooltip-max-width:220px;--bs-tooltip-padding-x:10px;--bs-tooltip-padding-y:6px;
  --bs-tooltip-font-size:.8125rem;--bs-tooltip-border-radius:8px;--bs-tooltip-arrow-width:12px;--bs-tooltip-arrow-height:6px;font-family:inherit;filter:drop-shadow(0 10px 16px rgba(0,0,0,.45))}
.tooltip.tt .tooltip-inner{text-align:left;font-weight:600;line-height:1.45}
.tooltip.tt-slate{--bs-tooltip-bg:#1e293b;--bs-tooltip-color:#f1f5f9;filter:drop-shadow(0 0 .7px #64748b) drop-shadow(0 12px 18px rgba(0,0,0,.5))}
.tooltip.tt-slate .tooltip-inner{font-weight:500}
.tooltip.tt-slate b{display:block;color:#fff;font-weight:650}
.tooltip.tt-slate small{color:#cbd5e1;font-size:.75rem}
.tooltip.tt-glow{--bs-tooltip-bg:#082f3a;--bs-tooltip-color:#cffafe;--bs-tooltip-max-width:270px;filter:drop-shadow(0 0 .8px #22d3ee) drop-shadow(0 0 14px rgba(34,211,238,.4))}
.tooltip.tt-glow .tooltip-inner{font-weight:500}
.tooltip.tt-glow code{color:#67e8f9;font-size:.75rem;font-weight:600}
.tooltip.show{animation:tt-in .15s ease-out}
@keyframes tt-in{from{opacity:0}}

.rail{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0;--bs-nav-link-color:#94a3b8;--bs-nav-link-hover-color:#e2e8f0;gap:6px;padding:8px;border:1px solid #1f2a44;border-radius:16px;background:#0b1222}
.rail .nav-link{display:grid;place-items:center;width:42px;height:42px;border-radius:11px}
.rail .nav-link:hover{background:#18233a}
.rail .nav-link.active{background:#12324a;color:#67e8f9}
.rail svg{width:20px;height:20px}
.chart{display:flex;align-items:flex-end;gap:10px;height:200px;margin:0;padding:64px 0 0;list-style:none;border-bottom:1px solid #26324d}
.chart li{flex:1;display:flex;height:100%;align-items:flex-end}
.bar{display:block;width:100%;height:var(--h);border-radius:6px 6px 2px 2px;background:linear-gradient(#22d3ee,#0e7490);opacity:.75;transition:opacity .15s}
.bar:hover,.bar:focus-visible,.bar[aria-describedby],.bar.is-open{opacity:1}
.days{display:flex;gap:10px;margin:8px 0 0;padding:0;list-style:none;color:#94a3b8;font-size:.75rem;text-align:center}
.days li{flex:1}
.deploy{--bs-btn-padding-x:16px;--bs-btn-font-size:.875rem;--bs-btn-font-weight:600;--bs-btn-line-height:1;--bs-btn-border-radius:10px;--bs-btn-color:#ecfeff;--bs-btn-border-color:#155e75;
  --bs-btn-hover-color:#ecfeff;--bs-btn-hover-border-color:#155e75;--bs-btn-active-color:#ecfeff;--bs-btn-active-border-color:#155e75;display:inline-flex;align-items:center;gap:8px;height:40px;
  background:linear-gradient(#0e7490,#155e75);box-shadow:0 0 0 1px rgba(34,211,238,.15),0 8px 24px -8px rgba(34,211,238,.5)}
.deploy:hover{background:linear-gradient(#0891b2,#0e7490)}
.deploy svg{width:16px;height:16px}
.live{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 12px;border:1px solid #1f2a44;background:#0b1222;color:#e2e8f0;font-size:.8125rem;font-weight:600;line-height:1;cursor:help}
.live i{width:8px;height:8px;border-radius:50%;background:#4ade80;box-shadow:0 0 0 3px rgba(74,222,128,.2)}
:is(.rail .nav-link,.bar,.deploy,.live):focus-visible{outline:2px solid #67e8f9;outline-offset:2px;box-shadow:none}
@media (prefers-reduced-motion:reduce){.tooltip.show{animation:none}.rail .nav-link,.bar,.btn{transition:none}}
JavaScript
// Bootstrap Tooltip (animation off, CSS fades it in), triggered by this script so it meets WCAG 1.4.13: it opens on hover,
// keyboard focus and tap, stays open while the pointer is on it, Esc closes it, and only one is open at a time.
// data-tt-label: the element's aria-label already says what the tooltip says, so Bootstrap's aria-describedby is dropped.
(() => {
  const tips = new Map();
  const hideAll = keep => tips.forEach(t => t !== keep && t.hide());
  document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
    const tip = new bootstrap.Tooltip(el, { trigger: 'manual', animation: false, offset: [0, 10],
      customClass: ('tt ' + (el.dataset.bsCustomClass || '')).trim() });
    tips.set(el, tip);
    let open = false, timer;
    el.addEventListener('show.bs.tooltip', () => { open = true; el.classList.add('is-open'); });
    el.addEventListener('hide.bs.tooltip', () => { open = false; el.classList.remove('is-open'); });
    el.addEventListener('inserted.bs.tooltip', () => {
      if ('ttLabel' in el.dataset) el.removeAttribute('aria-describedby');
      tip.tip.addEventListener('mouseenter', () => clearTimeout(timer));
      tip.tip.addEventListener('mouseleave', leave);
    });
    const show = () => { clearTimeout(timer); hideAll(tip); if (!open) tip.show(); };
    const leave = () => { clearTimeout(timer); timer = setTimeout(() => { if (el !== document.activeElement) tip.hide(); }, 150); };
    el.addEventListener('mouseenter', show);
    el.addEventListener('focus', () => { clearTimeout(timer); if (!open) tip.show(); });
    el.addEventListener('mouseleave', leave);
    el.addEventListener('blur', () => { if (!el.matches(':hover')) tip.hide(); });
  });
  document.addEventListener('pointerdown', e => { if (![...tips.keys()].some(el => el.contains(e.target)) && !e.target.closest('.tooltip')) hideAll(); });
  document.addEventListener('keydown', e => { if (e.key === 'Escape') hideAll(); });
})();

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="i-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5 12 4l8 6.5V19a1 1 0 0 1-1 1h-4.5v-6h-5v6H5a1 1 0 0 1-1-1z"/></symbol>
  <symbol id="i-chart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20V4M4 20h16M8 16v-5M12 16V8M16 16v-3"/></symbol>
  <symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8.5" r="3.5"/><path d="M2.5 20c.6-3.6 3.2-5.5 6.5-5.5s5.9 1.9 6.5 5.5"/><path d="M16 5.2a3.3 3.3 0 0 1 0 6.6M18 14.8c2 .6 3.2 2.3 3.5 5.2"/></symbol>
  <symbol id="i-card" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5.5" width="18" height="13" rx="2.5"/><path d="M3 10h18M7 15h3"/></symbol>
  <symbol id="i-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 3v2.5M12 18.5V21M3 12h2.5M18.5 12H21M5.6 5.6l1.8 1.8M16.6 16.6l1.8 1.8M5.6 18.4l1.8-1.8M16.6 7.4l1.8-1.8"/></symbol>
  <symbol id="i-rocket" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15.5 8.5 12C10 7 13.5 4 19.5 4.5 20 10.5 17 14 12 15.5z"/><path d="M8.5 12 5 11.5 7.5 8.5h3.5M12 15.5l.5 3.5 3-2.5V13"/><circle cx="15" cy="9" r="1.2"/></symbol>
</svg>

<div><span class="mb-[14px] block text-[.72rem] tracking-[.12em] text-[#94a3b8] uppercase">Icon rail labels</span>
<div class="rounded-[18px] border border-[#1f2a44] bg-[#111a2e] p-7 max-[600px]:p-5 min-h-[330px]">
  <nav aria-label="Main">
    <ul class="m-0 inline-flex list-none flex-col gap-1.5 rounded-2xl border border-[#1f2a44] bg-[#0b1222] p-2">
      <li><span class="tt relative inline-flex align-middle"><a class="grid size-[42px] place-items-center rounded-[11px] text-[#94a3b8] transition-colors duration-150 hover:bg-[#18233a] hover:text-[#e2e8f0] aria-[current=page]:bg-[#12324a] aria-[current=page]:text-[#67e8f9] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" href="#overview" aria-labelledby="rl-1"><svg class="size-5" aria-hidden="true"><use href="#i-home"/></svg></a><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-semibold text-tt-ink whitespace-normal [filter:drop-shadow(0_10px_16px_rgba(0,0,0,.45))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] left-[calc(100%+10px)] top-1/2 -translate-y-1/2 before:right-full before:top-[calc(50%-6px)] before:border-l-0 before:border-r-tt after:inset-y-0 after:right-full after:w-[10px]" role="tooltip" id="rl-1">Overview</span></span></li>
      <li><span class="tt relative inline-flex align-middle" id="tt-rail"><a class="grid size-[42px] place-items-center rounded-[11px] text-[#94a3b8] transition-colors duration-150 hover:bg-[#18233a] hover:text-[#e2e8f0] aria-[current=page]:bg-[#12324a] aria-[current=page]:text-[#67e8f9] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" href="#analytics" aria-current="page" aria-labelledby="rl-2"><svg class="size-5" aria-hidden="true"><use href="#i-chart"/></svg></a><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-semibold text-tt-ink whitespace-normal [filter:drop-shadow(0_10px_16px_rgba(0,0,0,.45))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] left-[calc(100%+10px)] top-1/2 -translate-y-1/2 before:right-full before:top-[calc(50%-6px)] before:border-l-0 before:border-r-tt after:inset-y-0 after:right-full after:w-[10px]" role="tooltip" id="rl-2">Analytics</span></span></li>
      <li><span class="tt relative inline-flex align-middle"><a class="grid size-[42px] place-items-center rounded-[11px] text-[#94a3b8] transition-colors duration-150 hover:bg-[#18233a] hover:text-[#e2e8f0] aria-[current=page]:bg-[#12324a] aria-[current=page]:text-[#67e8f9] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" href="#customers" aria-labelledby="rl-3"><svg class="size-5" aria-hidden="true"><use href="#i-users"/></svg></a><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-semibold text-tt-ink whitespace-normal [filter:drop-shadow(0_10px_16px_rgba(0,0,0,.45))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] left-[calc(100%+10px)] top-1/2 -translate-y-1/2 before:right-full before:top-[calc(50%-6px)] before:border-l-0 before:border-r-tt after:inset-y-0 after:right-full after:w-[10px]" role="tooltip" id="rl-3">Customers</span></span></li>
      <li><span class="tt relative inline-flex align-middle"><a class="grid size-[42px] place-items-center rounded-[11px] text-[#94a3b8] transition-colors duration-150 hover:bg-[#18233a] hover:text-[#e2e8f0] aria-[current=page]:bg-[#12324a] aria-[current=page]:text-[#67e8f9] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" href="#billing" aria-labelledby="rl-4"><svg class="size-5" aria-hidden="true"><use href="#i-card"/></svg></a><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-semibold text-tt-ink whitespace-normal [filter:drop-shadow(0_10px_16px_rgba(0,0,0,.45))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] left-[calc(100%+10px)] top-1/2 -translate-y-1/2 before:right-full before:top-[calc(50%-6px)] before:border-l-0 before:border-r-tt after:inset-y-0 after:right-full after:w-[10px]" role="tooltip" id="rl-4">Billing</span></span></li>
      <li><span class="tt relative inline-flex align-middle"><a class="grid size-[42px] place-items-center rounded-[11px] text-[#94a3b8] transition-colors duration-150 hover:bg-[#18233a] hover:text-[#e2e8f0] aria-[current=page]:bg-[#12324a] aria-[current=page]:text-[#67e8f9] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" href="#settings" aria-labelledby="rl-5"><svg class="size-5" aria-hidden="true"><use href="#i-gear"/></svg></a><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-semibold text-tt-ink whitespace-normal [filter:drop-shadow(0_10px_16px_rgba(0,0,0,.45))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] left-[calc(100%+10px)] top-1/2 -translate-y-1/2 before:right-full before:top-[calc(50%-6px)] before:border-l-0 before:border-r-tt after:inset-y-0 after:right-full after:w-[10px]" role="tooltip" id="rl-5">Settings</span></span></li>
    </ul>
  </nav>
</div></div>

<div><span class="mb-[14px] block text-[.72rem] tracking-[.12em] text-[#94a3b8] uppercase">Values on a chart</span>
<div class="rounded-[18px] border border-[#1f2a44] bg-[#111a2e] p-7 max-[600px]:p-5 min-h-[330px]">
  <ul class="m-0 flex h-[200px] list-none items-end gap-2.5 border-b border-[#26324d] p-0 pt-16" aria-label="Sessions per day, 13 to 19 October">
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[46%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Monday 13 October: 1,062 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Mon 13 Oct</b><small class="text-xs text-[#cbd5e1]">1,062 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[58%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Tuesday 14 October: 1,284 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Tue 14 Oct</b><small class="text-xs text-[#cbd5e1]">1,284 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[64%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Wednesday 15 October: 1,410 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Wed 15 Oct</b><small class="text-xs text-[#cbd5e1]">1,410 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[88%]" id="tt-bar"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Thursday 16 October: 1,912 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Thu 16 Oct</b><small class="text-xs text-[#cbd5e1]">1,912 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[70%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Friday 17 October: 1,536 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Fri 17 Oct</b><small class="text-xs text-[#cbd5e1]">1,536 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[33%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Saturday 18 October: 731 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Sat 18 Oct</b><small class="text-xs text-[#cbd5e1]">731 sessions</small></span></span></li>
    <li class="flex h-full flex-1 flex-col justify-end"><span class="tt relative inline-flex align-middle flex! h-[44%]"><span class="block flex-1 rounded-t-md rounded-b-xs bg-linear-to-b from-[#22d3ee] to-[#0e7490] opacity-75 transition-opacity duration-150 hover:opacity-100 focus-visible:opacity-100 in-[.is-open]:opacity-100 motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" tabindex="0" role="img" aria-label="Sunday 19 October: 969 sessions"></span><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-top bottom-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:top-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-b-0 before:border-t-tt-slate after:inset-x-0 after:top-full after:h-[10px]" aria-hidden="true"><b class="block font-[650] text-white">Sun 19 Oct</b><small class="text-xs text-[#cbd5e1]">969 sessions</small></span></span></li>
  </ul>
  <ul class="m-0 mt-2 flex list-none gap-2.5 p-0 text-center text-xs text-[#94a3b8]" aria-hidden="true"><li class="flex-1">M</li><li class="flex-1">T</li><li class="flex-1">W</li><li class="flex-1">T</li><li class="flex-1">F</li><li class="flex-1">S</li><li class="flex-1">S</li></ul>
  <p class="mt-3.5 mb-0 text-[.8125rem] text-[#cbd5e1]">This week <b class="text-white">8,904 sessions</b>, peak on Thursday.</p>
</div></div>

<div class="col-span-full"><span class="mb-[14px] block text-[.72rem] tracking-[.12em] text-[#94a3b8] uppercase">Glow accent</span>
<div class="rounded-[18px] border border-[#1f2a44] bg-[#111a2e] p-7 max-[600px]:p-5">
  <div class="flex flex-wrap items-center gap-x-7 gap-y-5 pb-[58px]">
    <span class="tt relative inline-flex align-middle" id="tt-deploy"><button class="inline-flex h-10 cursor-pointer items-center gap-2 rounded-[10px] border border-[#155e75] bg-linear-to-b from-[#0e7490] to-[#155e75] px-4 text-sm leading-none font-semibold text-[#ecfeff] shadow-[0_0_0_1px_rgba(34,211,238,.15),0_8px_24px_-8px_rgba(34,211,238,.5)] hover:from-[#0891b2] hover:to-[#0e7490] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" type="button" aria-describedby="tip-deploy"><svg class="size-4" aria-hidden="true"><use href="#i-rocket"/></svg>Deploy</button><span class="pointer-events-auto absolute z-30 w-max max-w-[270px] rounded-lg bg-tt-glow px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-glow-ink whitespace-normal [filter:drop-shadow(0_0_.8px_#22d3ee)_drop-shadow(0_0_14px_rgba(34,211,238,.4))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-bottom top-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:bottom-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-t-0 before:border-b-tt-glow after:inset-x-0 after:bottom-full after:h-[10px]" role="tooltip" id="tip-deploy"><code class="font-mono text-xs font-semibold text-[#67e8f9]">main</code> to production, 3 new commits</span></span>
    <span class="tt relative inline-flex align-middle"><button class="inline-flex h-8 cursor-help items-center gap-2 rounded-full border border-[#1f2a44] bg-[#0b1222] px-3 text-[.8125rem] leading-none font-semibold text-[#e2e8f0] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#67e8f9]" type="button" aria-describedby="tip-live"><i class="size-2 rounded-full bg-[#4ade80] shadow-[0_0_0_3px_rgba(74,222,128,.2)]" aria-hidden="true"></i>214 online</button><span class="pointer-events-auto absolute z-30 w-max max-w-[220px] rounded-lg bg-tt-slate px-2.5 py-1.5 text-[.8125rem] leading-[1.45] font-medium text-tt-slate-ink whitespace-normal [filter:drop-shadow(0_0_.7px_#64748b)_drop-shadow(0_12px_18px_rgba(0,0,0,.5))] before:absolute before:border-transparent after:absolute before:border-[6px] invisible opacity-0 scale-0 tt-open:visible tt-open:opacity-100 tt-open:scale-100 motion-safe:[transition:opacity_.15s,visibility_.15s,scale_0s_.15s] motion-safe:tt-open:[transition:opacity_.15s,visibility_0s,scale_0s] tt-bottom top-[calc(100%+10px)] left-1/2 translate-x-[calc(-50%+var(--tt-nudge,0px))] before:bottom-full before:left-[calc(50%-6px-var(--tt-nudge,0px))] before:border-t-0 before:border-b-tt-slate after:inset-x-0 after:bottom-full after:h-[10px]" role="tooltip" id="tip-live">People with the app open in the last 5 minutes</span></span>
  </div>
</div></div>
CSS
@theme {
  --color-tt: #e2e8f0;
  --color-tt-ink: #0b1120;
  --color-tt-slate: #1e293b;
  --color-tt-slate-ink: #f1f5f9;
  --color-tt-glow: #082f3a;
  --color-tt-glow-ink: #cffafe;
}
/* tt-open: a tooltip inside a .tt wrapper that is hovered, holds focus or was opened by tap, and was not dismissed with Esc. */
@custom-variant tt-open (&:is(:where(.tt):is(:hover, :focus-within, .is-open):not(.is-dismissed) > *));
JavaScript
// Tooltip behaviour for WCAG 1.4.13: Esc dismisses without moving focus or the pointer, a tap opens it on touch screens,
// opening one closes the others, and top/bottom tooltips are nudged sideways to stay inside the window.
(() => {
  const tts = [...document.querySelectorAll('.tt')];
  const fit = t => {
    const tip = t.querySelector(':scope > .tt-top, :scope > .tt-bottom'); if (!tip) return;
    tip.style.removeProperty('--tt-nudge');
    requestAnimationFrame(() => {
      const r = tip.getBoundingClientRect(), w = document.documentElement.clientWidth;
      const d = r.left < 8 ? 8 - r.left : r.right > w - 8 ? w - 8 - r.right : 0;
      if (d) tip.style.setProperty('--tt-nudge', d + 'px');
    });
  };
  const enter = t => { tts.forEach(o => o !== t && o.classList.remove('is-open')); t.classList.remove('is-dismissed'); fit(t); };
  tts.forEach(t => { t.addEventListener('pointerenter', () => enter(t)); t.addEventListener('focusin', () => enter(t)); if (t.classList.contains('is-open')) fit(t); });
  document.addEventListener('pointerdown', e => {
    const t = e.target.closest('.tt');
    if (!t) tts.forEach(o => o.classList.remove('is-open'));
    else if (e.pointerType === 'touch') t.classList.add('is-open');
  });
  document.addEventListener('keydown', e => {
    if (e.key !== 'Escape') return;
    tts.filter(t => t.matches(':hover, :focus-within, .is-open')).forEach(t => { t.classList.remove('is-open'); t.classList.add('is-dismissed'); });
  });
})();

About this set

Tooltips for dark dashboards, where a black tooltip disappears into a near-black page. Icon rail labels gives a five-icon navigation rail, from Overview to Settings, light labels that open to the right; each link takes its accessible name from its label, and the current page is marked with aria-current. Values on a chart puts a tooltip with the date and the session count on each bar of a weekly chart; every bar can be reached with Tab, its aria-label carries the same figures, and a visible summary line gives the weekly total and the peak day, so no number exists only in a tooltip. Glow accent gives a Deploy button a dark cyan tooltip whose outline and glow come from filter: drop-shadow, which follows the arrow, and an online counter an outlined slate tooltip. Use the light labels for short names, the outlined slate for data, and the glow sparingly for the primary action. Colours are checked for contrast against the #0b1120 page. The Bootstrap version runs in data-bs-theme=”dark” with Bootstrap Tooltip and custom classes.

What’s included

  • Light labels on an icon rail
  • Chart bar tooltips with date and value
  • Outlined slate and cyan glow tooltips
  • Outlines drawn with filter: drop-shadow, arrow included
  • Chart figures also in aria-labels and a visible summary
  • Bootstrap in data-bs-theme="dark"

Accessibility

Rail links are named by their labels through aria-labelledby, and the current one has aria-current="page". Chart bars are focusable images whose aria-label holds the day and value, so their tooltips are hidden from screen readers, and the week's total is visible text. Tooltips open on hover and focus, close with Esc, and stay open under the pointer; focus outlines are bright cyan and transitions stop under prefers-reduced-motion.

Customise it

Plain CSS sets --tt-bg and --tt-ink on .tt-tip, .tt-slate and .tt-glow, and the outline colour inside each filter. In Bootstrap the same values are --bs-tooltip-bg and --bs-tooltip-color on .tooltip.tt-slate and .tooltip.tt-glow. In Tailwind edit the --color-tt-* theme colours and the [filter:...] utilities.