Browse Components
Tooltips
Small, contextual hints on hover, focus, or touch.
Basic
A short hint on hover, keyboard focus, or touch. Escape dismisses it.
View Code
<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.
View Code
<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
<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
<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
<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.
View Code
<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.
<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.