Browse Components

Tooltips

Small, contextual hints on hover, focus, or touch.

Basic

A short hint on hover, keyboard focus, or touch. Escape dismisses it.

A little context, right where you need it.
View Code
HTML
<button class="btn secondary" type="button" data-tooltip="top" aria-describedby="tip-top">
  Top
</button>
<span class="tooltip" id="tip-top" role="tooltip" popover="manual">
  A little context, right where you need it.
</span>

Positions

Choose a preferred side. The tooltip adjusts when there is not enough room.

A little context, right where you need it.A little context, right where you need it.A little context, right where you need it.A little context, right where you need it.
View Code
HTML
<div class="cluster" style="padding:48px 0">
  <button
    class="btn secondary"
    type="button"
    data-tooltip="top"
    aria-describedby="tip-top"
  >
    Top
  </button>
  <span class="tooltip" id="tip-top" role="tooltip" popover="manual">
    A little context, right where you need it.
  </span>
  <button
    class="btn secondary"
    type="button"
    data-tooltip="right"
    aria-describedby="tip-right"
  >
    Right
  </button>
  <span class="tooltip" id="tip-right" role="tooltip" popover="manual">
    A little context, right where you need it.
  </span>
  <button
    class="btn secondary"
    type="button"
    data-tooltip="bottom"
    aria-describedby="tip-bottom"
  >
    Bottom
  </button>
  <span class="tooltip" id="tip-bottom" role="tooltip" popover="manual">
    A little context, right where you need it.
  </span>
  <button
    class="btn secondary"
    type="button"
    data-tooltip="left"
    aria-describedby="tip-left"
  >
    Left
  </button>
  <span class="tooltip" id="tip-left" role="tooltip" popover="manual">
    A little context, right where you need it.
  </span>
</div>

Edges and corners

Try every edge. Tooltips flip and shift to stay inside the frame.

View Code
HTML
<style>
  html,body{height:100%;margin:0}
.tooltip-demo{direction:ltr;height:100%;min-height:320px;padding:12px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:repeat(3,1fr);gap:8px}
.tooltip-demo>div{display:flex;align-items:center;justify-content:center;min-width:0}
.tooltip-demo>div:nth-child(-n+3){align-items:flex-start}
.tooltip-demo>div:nth-child(n+7){align-items:flex-end}
.tooltip-demo>div:nth-child(3n+1){justify-content:flex-start}
.tooltip-demo>div:nth-child(3n){justify-content:flex-end}
.tooltip-demo .btn{padding:8px 12px;font-size:.8125rem;white-space:normal;text-align:center}
:root[dir=rtl] .tooltip-demo :is(button,.tooltip){direction:rtl}
</style>
<main class="tooltip-demo" aria-label="Tooltip positioning examples">
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-tl"
    >
      Top Left
    </button>
    <span class="tooltip" id="demo-tl" role="tooltip" popover="manual">
      I flip below and shift away from the left edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-top"
    >
      Top Edge
    </button>
    <span class="tooltip" id="demo-top" role="tooltip" popover="manual">
      No room above? I move below the button.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-tr"
    >
      Top Right
    </button>
    <span class="tooltip" id="demo-tr" role="tooltip" popover="manual">
      I flip below and shift away from the right edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="left"
      aria-describedby="demo-left"
    >
      Left Edge
    </button>
    <span class="tooltip" id="demo-left" role="tooltip" popover="manual">
      I prefer the left, but move right when space is tight.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-center"
    >
      Center
    </button>
    <span class="tooltip" id="demo-center" role="tooltip" popover="manual">
      With room to spare, I stay in my preferred position.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="right"
      aria-describedby="demo-right"
    >
      Right Edge
    </button>
    <span class="tooltip" id="demo-right" role="tooltip" popover="manual">
      I prefer the right, but move left when space is tight.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-bl"
    >
      Bottom Left
    </button>
    <span class="tooltip" id="demo-bl" role="tooltip" popover="manual">
      I flip above and stay inside the left edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-bottom"
    >
      Bottom Edge
    </button>
    <span class="tooltip" id="demo-bottom" role="tooltip" popover="manual">
      No room below? I move above the button.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-br"
    >
      Bottom Right
    </button>
    <span class="tooltip" id="demo-br" role="tooltip" popover="manual">
      I flip above and stay inside the right edge.
    </span>
  </div>
</main>

Fade and slide

Tooltips fade and slide 4px using shared 300ms timing. Try the edges: movement follows the final position after flipping. Escape dismisses without moving focus.

View Code
HTML
<style>
  html,body{height:100%;margin:0}
.tooltip-demo{direction:ltr;height:100%;min-height:320px;padding:12px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:repeat(3,1fr);gap:8px}
.tooltip-demo>div{display:flex;align-items:center;justify-content:center;min-width:0}
.tooltip-demo>div:nth-child(-n+3){align-items:flex-start}
.tooltip-demo>div:nth-child(n+7){align-items:flex-end}
.tooltip-demo>div:nth-child(3n+1){justify-content:flex-start}
.tooltip-demo>div:nth-child(3n){justify-content:flex-end}
.tooltip-demo .btn{padding:8px 12px;font-size:.8125rem;white-space:normal;text-align:center}
:root[dir=rtl] .tooltip-demo :is(button,.tooltip){direction:rtl}
</style>
<main class="tooltip-demo" aria-label="Tooltip positioning examples">
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-tl"
    >
      Top Left
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-tl"
      role="tooltip"
      popover="manual"
    >
      I flip below and shift away from the left edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-top"
    >
      Top Edge
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-top"
      role="tooltip"
      popover="manual"
    >
      No room above? I move below the button.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-tr"
    >
      Top Right
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-tr"
      role="tooltip"
      popover="manual"
    >
      I flip below and shift away from the right edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="left"
      aria-describedby="demo-left"
    >
      Left Edge
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-left"
      role="tooltip"
      popover="manual"
    >
      I prefer the left, but move right when space is tight.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="top"
      aria-describedby="demo-center"
    >
      Center
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-center"
      role="tooltip"
      popover="manual"
    >
      With room to spare, I stay in my preferred position.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="right"
      aria-describedby="demo-right"
    >
      Right Edge
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-right"
      role="tooltip"
      popover="manual"
    >
      I prefer the right, but move left when space is tight.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-bl"
    >
      Bottom Left
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-bl"
      role="tooltip"
      popover="manual"
    >
      I flip above and stay inside the left edge.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-bottom"
    >
      Bottom Edge
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-bottom"
      role="tooltip"
      popover="manual"
    >
      No room below? I move above the button.
    </span>
  </div>
  <div>
    <button
      class="btn secondary"
      type="button"
      data-tooltip="bottom"
      aria-describedby="demo-br"
    >
      Bottom Right
    </button>
    <span
      class="tooltip"
      data-effect="slide"
      id="demo-br"
      role="tooltip"
      popover="manual"
    >
      I flip above and stay inside the right edge.
    </span>
  </div>
</main>

Right-to-left

Translate the hint and set direction and language on its containing element. Left and right are physical placement preferences, not logical start/end.

מידע נוסף על האפשרות הזאת.
View Code
HTML
<div dir="rtl" lang="he">
  <button
    class="btn secondary"
    type="button"
    data-tooltip="top"
    aria-describedby="tip-he"
  >
    עזרה
  </button>
  <span class="tooltip" id="tip-he" role="tooltip" popover="manual">
    מידע נוסף על האפשרות הזאת.
  </span>
</div>

Without motion

Put data-motion=none on a wrapper containing both trigger and tooltip. Reduced-motion preferences disable both effects.

A hint that appears immediately.
View Code
HTML
<div data-motion="none">
  <button
    class="btn secondary"
    type="button"
    data-tooltip="top"
    aria-describedby="tip-still"
  >
    Preview
  </button>
  <span
    class="tooltip"
    id="tip-still"
    data-effect="slide"
    role="tooltip"
    popover="manual"
  >
    A hint that appears immediately.
  </span>
</div>

Installation

Download these files into the matching paths in your project, or use Create to assemble a kit. Include each dependency once. Do not also load app.css.

Add to your page
<link rel="stylesheet" href="/library/assets/base.css">
<link rel="stylesheet" href="/library/assets/button.css">
<link rel="stylesheet" href="/library/assets/tooltip.css">
<script defer src="/library/assets/tooltip.js"></script>

11,335 bytes CSS including base · 3,858 bytes runtime JavaScript

Usage

Add a little context

Connect the trigger to a unique tooltip ID with aria-describedby. Put data-tooltip="top" on the trigger to choose a preferred side.

Keep help accessible

Tooltips open on hover, focus, or touch; Escape dismisses them. Keep essential instructions visible and avoid links or buttons inside the hint.

Choose the motion

Tooltips keep a simple theme-aware surface and arrow across styles, and fade and slide 4px. Both effects respect reduced motion. Include the tooltip script once.

Building with AI? The AI Manifest has these notes and the full contract. See the AI Guide.