Tooltip Examples
The examples below assume that you have imported the component and set up the theme.
With the default triggers, tooltips never reveal on touch devices. Use trigger="click" on a tooltip icon, or trigger="long-press" on a control that already does something, to reach touch users.
Basic
Attach a tooltip with data-sv-tooltip naming the tooltip's id. Hover or focus the button to reveal it.
<div class="tooltip-basic"> <button type="button" aria-describedby="tooltip-save" data-sv-tooltip="tooltip-save">Save</button> <sv-tooltip id="tooltip-save">Writes the draft to disk</sv-tooltip></div>
<style> .tooltip-basic { display: flex; justify-content: center; padding-block: 2em;
button { padding: 0.2em 1em; font: inherit; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>Placement
side picks which side of the anchor element to try first. The tooltip is always centered on the anchor element along that side.
<div class="tooltip-placement"> <button type="button" aria-describedby="place-top" data-sv-tooltip="place-top">side="block-start"</button> <sv-tooltip id="place-top" reveal-delay="0" side="block-start">Placed above</sv-tooltip>
<button type="button" aria-describedby="place-bottom" data-sv-tooltip="place-bottom">side="block-end"</button> <sv-tooltip id="place-bottom" reveal-delay="0" side="block-end">Placed below</sv-tooltip>
<button type="button" aria-describedby="place-left" data-sv-tooltip="place-left">side="inline-start"</button> <sv-tooltip id="place-left" reveal-delay="0" side="inline-start">Placed at the inline start</sv-tooltip>
<button type="button" aria-describedby="place-right" data-sv-tooltip="place-right">side="inline-end"</button> <sv-tooltip id="place-right" reveal-delay="0" side="inline-end">Placed at the inline end</sv-tooltip></div>
<style> .tooltip-placement { display: grid; grid-template-columns: repeat(2, max-content); gap: 4em 1em; justify-content: center; padding-block: 4em;
@media (max-width: 400px) { grid-template-columns: repeat(1, max-content); }
button { padding: 0.4em 1em; font: inherit; font-family: monospace; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>Trigger
trigger picks how the element reveals its tooltip. click suits an element whose only job is revealing the tooltip, and since taps count as clicks, it also works on touch devices.
<div class="tooltip-trigger"> <span>Storage region</span>
<button type="button" aria-describedby="tooltip-info" aria-label="About storage region" data-sv-tooltip="tooltip-info"> <svg aria-hidden="true" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24"> <path d="M12 2a10 10 0 1 0 0 20 10 10 0 1 0 0-20Zm-1 5h2v2h-2V7Zm0 4h2v6h-2v-6Z" /> </svg> </button>
<sv-tooltip id="tooltip-info" trigger="click">Data is stored in the region closest to you</sv-tooltip></div>
<style> .tooltip-trigger { display: flex; gap: 0.25em; align-items: center; justify-content: center; padding-block: 2em;
button { display: inline-flex; padding: 0.2em; color: var(--sv-gray-3); cursor: pointer; background: none; border: none; border-radius: 50%;
svg { inline-size: 1.4em; } }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>Long Press
trigger="long-press" reveals the tooltip after the element is held down, and keeps it open until a press outside it or Escape. The tap itself stays free, so it suits a control that already does something. Press and hold also works with a mouse or a pen.
long-press-delay sets how long the hold has to last.
Long pressing can start a text selection or open the platform callout, so the buttons here turn user-select off.
<div class="tooltip-long-press"> <button type="button" aria-describedby="tooltip-bold" aria-label="Bold" data-sv-tooltip="tooltip-bold">B</button> <sv-tooltip id="tooltip-bold" trigger="long-press">Bold (⌘B)</sv-tooltip>
<button type="button" aria-describedby="tooltip-italic" aria-label="Italic" data-sv-tooltip="tooltip-italic">I</button> <sv-tooltip id="tooltip-italic" trigger="long-press">Italic (⌘I)</sv-tooltip>
<button type="button" aria-describedby="tooltip-underline" aria-label="Underline" data-sv-tooltip="tooltip-underline">U</button> <sv-tooltip id="tooltip-underline" trigger="long-press">Underline (⌘U)</sv-tooltip></div>
<style> .tooltip-long-press { display: flex; gap: 0.5em; justify-content: center; padding-block: 2em;
button { inline-size: 2.4em; block-size: 2.4em; font: inherit; font-weight: 700; color: var(--sv-gray-2); cursor: pointer; user-select: none; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>Scrolling
The tooltip keeps up with its anchor element while the page or a scroll container moves, with no JavaScript in the loop.
Placement is a preference, not a guarantee. Fallbacks are measured against the viewport rather than the scroll container, so a tooltip flips when the anchor element nears the edge of the window.
<div class="tooltip-scrolling"> <div class="tooltip-scroller"> <div class="tooltip-canvas"> <button type="button" aria-describedby="tooltip-scroll" data-sv-tooltip="tooltip-scroll">Scroll me around</button> </div> </div>
<sv-tooltip id="tooltip-scroll" reveal-delay="0">Anchored with CSS only</sv-tooltip></div>
<style> .tooltip-scrolling { .tooltip-scroller { block-size: 12rem; overflow: auto; overscroll-behavior: contain; background-color: var(--sv-gray-7); border: solid 1px var(--sv-gray-6); border-radius: var(--sv-bdr-rad-md); }
.tooltip-canvas { display: flex; align-items: start; justify-content: center; block-size: 30rem; padding-block-start: 4rem; }
button { padding: 0.5em 1em; font: inherit; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>Styling
The tooltip is the popover itself, so custom properties and CSS on sv-tooltip apply directly, and the slot takes any non-interactive markup.
<div class="tooltip-styling"> <button type="button" aria-describedby="tooltip-delete-styled" data-sv-tooltip="tooltip-delete-styled">Delete</button>
<sv-tooltip id="tooltip-delete-styled" side="inline-end"> <span class="tooltip-danger"> <svg aria-hidden="true" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24"> <path d="M12 2 1 21h22L12 2Zm-1 7h2v5h-2V9Zm0 7h2v2h-2v-2Z" /> </svg> Cannot be undone </span> </sv-tooltip></div>
<style> .tooltip-styling { display: flex; justify-content: center; padding-block: 2em;
button { padding: 0.5em 1em; font: inherit; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { --sv-tooltip-offset: 1em; --sv-tooltip-bdr-clr: crimson;
font-size: 0.875em; white-space: nowrap; }
.tooltip-danger { display: flex; gap: 0.4em; align-items: center;
svg { inline-size: 1em; color: crimson; } } }</style>Animation
--sv-tooltip-dur and --sv-tooltip-ease reshape the built-in opacity transition. The spring tooltip adds a scale on top. The slide tooltip replaces the animated properties instead: closed values on sv-tooltip, open values and @starting-style under :popover-open, and a transition-property that keeps display and overlay so the hide transition still plays.
End a transform at none, not at 1 or 0 0. While the tooltip carries a transform the arrow sits centered on its edge, and only a transform-free tooltip lets it point at the element.
Overriding --sv-tooltip-dur from the page also overrides the component's reduced motion fallback, so restore it yourself.
Your system is set to reduce motion, so this animation will not play for you.
<div class="tooltip-animation"> <button type="button" aria-describedby="tooltip-slide" data-sv-tooltip="tooltip-slide">Slide</button> <sv-tooltip id="tooltip-slide" class="slide" reveal-delay="0">Slides in from below</sv-tooltip>
<button type="button" aria-describedby="tooltip-spring" data-sv-tooltip="tooltip-spring">Spring</button> <sv-tooltip id="tooltip-spring" class="spring" reveal-delay="0" side="block-end">Bounces in with a spring easing</sv-tooltip></div>
<style> .tooltip-animation { display: flex; gap: 1em; justify-content: center; padding-block: 3em;
button { padding: 0.5em 1em; font: inherit; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; }
sv-tooltip.spring { --sv-tooltip-dur: 200ms; --sv-tooltip-ease: linear(0, 0.6 15%, 1.15 35%, 0.97 55%, 1.01 75%, 1);
scale: 0.5; transition-property: opacity, scale, display, overlay; }
sv-tooltip.spring:popover-open { scale: none;
@starting-style { scale: 0.5; } }
sv-tooltip.slide { opacity: 0; translate: 0 0.75rem; transition-property: opacity, translate, display, overlay; }
sv-tooltip.slide:popover-open { opacity: 1; translate: none;
@starting-style { opacity: 0; translate: 0 0.75rem; } }
@media (prefers-reduced-motion: reduce) { sv-tooltip.spring { --sv-tooltip-dur: 0ms; } } }</style>Programmatic
Assign targets to attach a tooltip from JavaScript, with no data-sv-tooltip or id. open() reveals the tooltip immediately, used here as click feedback. beforetoggle restores the label the next time the tooltip opens, since restoring on close would swap the text mid fade-out.
<div class="tooltip-programmatic"> <button type="button">Save draft</button>
<sv-tooltip>Writes the draft to disk</sv-tooltip></div>
<script type="application/x-typescript" module> const tooltip = document.querySelector<Tooltip>(".tooltip-programmatic sv-tooltip")!; const button = document.querySelector<HTMLButtonElement>(".tooltip-programmatic button")!;
tooltip.targets = [button];
button.addEventListener("click", () => { tooltip.open(); tooltip.textContent = "Saved"; });
tooltip.addEventListener("beforetoggle", event => { if (event.newState === "open") { tooltip.textContent = "Writes the draft to disk"; } });</script>
<style> .tooltip-programmatic { display: flex; justify-content: center; padding-block: 2em;
button { padding: 0.3em 1em; font: inherit; color: var(--sv-gray-2); cursor: pointer; background-color: var(--sv-gray-5); border: none; border-radius: var(--sv-bdr-rad-md); }
sv-tooltip { font-size: 0.875em; white-space: nowrap; } }</style>