Component
Hotspot Tooltip
Onboarding hotspot beacon that opens a multi-step guided tour tooltip. Click the pulsing beacon to start; Next/Done walk the steps, Skip or Escape dismiss it.
- Component
- Tailwind
- HTML
- MIT
What it does
Capabilities
- Multi-step guided tour
- Pulsing beacon trigger
- Step progress segments
- Escape and outside-click dismiss
- Aria-expanded + role dialog
- Optional kbd hint per step
- Minimal-vercel design language
Preview
Live component
9:41 100%
devsnips.site/library/tailwind/components/tooltips/hotspot-tooltip/ fluid · no fixed width 100%
Install
Add to your project
npx devsnips add Tailwind/Components/Tooltips/hotspot-tooltip Tailwind/Components/Tooltips/hotspot-tooltip <!--
Snippet Name: Hotspot Tooltip
Description: Onboarding hotspot beacon with a multi-step tour tooltip. Click to open; Next/Skip walk the steps; Escape or outside click closes.
Author: DevSnips Contributors
Usage Example: Place the data-hotspot-tooltip wrapper next to the feature you announce, then edit the STEPS array in the script.
-->
<div class="relative inline-flex" data-hotspot-tooltip="hotspot-tooltip">
<button
type="button"
class="hs-trigger relative inline-flex h-8 w-8 items-center justify-center rounded-full bg-[#0a0a0a] ring-1 ring-white/10 transition-colors duration-150 hover:bg-[#111111] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#50e3c2] focus-visible:ring-offset-2 motion-reduce:transition-none"
aria-expanded="false"
aria-controls="hotspot-tip"
aria-label="What's new: start the tour"
>
<span aria-hidden="true" class="absolute inset-0 rounded-full bg-[#50e3c2]/40 motion-safe:animate-ping motion-reduce:animate-none"></span>
<span aria-hidden="true" class="relative h-2 w-2 rounded-full bg-[#50e3c2] shadow-[0_0_8px_rgba(80,227,194,0.9)]"></span>
</button>
<div
id="hotspot-tip"
role="dialog"
aria-labelledby="hotspot-tip-title"
class="absolute bottom-full left-1/2 mb-2.5 hidden w-72 max-w-[calc(100vw-2rem)] -translate-x-1/2 opacity-0 scale-95 transition-[opacity,transform] duration-150 ease-out motion-reduce:transition-none"
>
<div class="rounded-lg border border-white/10 bg-[#0a0a0a] shadow-[0_16px_48px_-12px_rgba(0,0,0,0.55)]">
<div class="flex items-start justify-between gap-3 p-4 pb-0">
<span class="hs-eyebrow inline-flex items-center gap-1.5 pt-0.5">
<span aria-hidden="true" class="h-1.5 w-1.5 rounded-full bg-[#50e3c2]"></span>
<span class="text-[11px] font-medium uppercase tracking-widest text-white/40">New feature</span>
</span>
<button
type="button"
class="hs-close -mr-1 -mt-0.5 rounded-md p-1 text-white/40 transition-colors duration-150 hover:bg-white/5 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-[#50e3c2] motion-reduce:transition-none"
aria-label="Close tour"
>
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
</div>
<div class="p-4 pb-0">
<h3 id="hotspot-tip-title" class="hs-title text-sm font-semibold tracking-tight text-white"></h3>
<p class="hs-desc mt-1.5 text-[13px] leading-relaxed text-white/60"></p>
<p class="hs-kbd-row mt-3 hidden items-center gap-1 text-[12px] text-white/40">
Try it:
<kbd class="hs-kbd ml-0.5 rounded border border-white/10 bg-white/5 px-1.5 py-0.5 font-sans text-[11px] font-medium text-white/70"></kbd>
</p>
</div>
<div class="flex items-center gap-3 p-4 pt-3">
<div class="hs-dots flex min-w-0 flex-1 items-center gap-1" aria-hidden="true"></div>
<span class="hs-counter text-[11px] tabular-nums text-white/40"></span>
<button
type="button"
class="hs-skip rounded-md px-2 py-1.5 text-xs font-medium text-white/50 transition-colors duration-150 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-[#50e3c2] motion-reduce:transition-none"
>Skip</button>
<button
type="button"
class="hs-next rounded-md bg-[#50e3c2] px-3 py-1.5 text-xs font-semibold text-[#0a0a0a] transition-colors duration-150 hover:bg-[#7cf0d5] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#50e3c2] focus-visible:ring-offset-2 focus-visible:ring-offset-[#0a0a0a] motion-reduce:transition-none"
>Next</button>
</div>
</div>
<span aria-hidden="true" class="absolute -bottom-1.5 left-1/2 h-3 w-3 -translate-x-1/2 rotate-45 border-b border-r border-white/10 bg-[#0a0a0a]"></span>
</div>
<script>
(function () {
var root = document.currentScript.closest('[data-hotspot-tooltip="hotspot-tooltip"]');
if (!root) return;
var STEPS = [
{
eyebrow: 'New feature',
title: 'Command palette',
desc: 'Jump to any snippet, page, or action without touching the mouse. One keystroke, zero navigation.',
keys: ['\u2318', 'K']
},
{
eyebrow: 'Saved views',
title: 'Pin your go-to snippets',
desc: 'Star the components you reach for daily and they stay pinned in the sidebar, synced across your devices.',
keys: null
},
{
eyebrow: 'Team workspace',
title: 'Share a curated library',
desc: 'Invite your team to one source of truth for snippets, with role-based access and usage insights.',
keys: null
}
];
var trigger = root.querySelector('.hs-trigger');
var tip = root.querySelector('#hotspot-tip');
var eyebrowEl = tip.querySelector('.hs-eyebrow span:last-child');
var titleEl = tip.querySelector('.hs-title');
var descEl = tip.querySelector('.hs-desc');
var kbdRow = tip.querySelector('.hs-kbd-row');
var kbdEl = tip.querySelector('.hs-kbd');
var dotsEl = tip.querySelector('.hs-dots');
var counterEl = tip.querySelector('.hs-counter');
var skipBtn = tip.querySelector('.hs-skip');
var nextBtn = tip.querySelector('.hs-next');
var closeBtn = tip.querySelector('.hs-close');
var current = 0;
var open = false;
var hideTimer = null;
function renderStep() {
var s = STEPS[current];
eyebrowEl.textContent = s.eyebrow;
titleEl.textContent = s.title;
descEl.textContent = s.desc;
if (s.keys) {
kbdEl.textContent = s.keys.join(' ');
kbdRow.classList.remove('hidden');
kbdRow.classList.add('flex');
} else {
kbdRow.classList.add('hidden');
kbdRow.classList.remove('flex');
}
dotsEl.innerHTML = STEPS.map(function (_, i) {
var active = i <= current;
return '<span class="h-1 flex-1 rounded-full ' + (active ? 'bg-[#50e3c2]' : 'bg-white/10') + '"></span>';
}).join('');
counterEl.textContent = (current + 1) + ' / ' + STEPS.length;
nextBtn.textContent = current === STEPS.length - 1 ? 'Done' : 'Next';
}
function setOpen(isOpen) {
open = isOpen;
trigger.setAttribute('aria-expanded', String(isOpen));
if (isOpen) {
renderStep();
if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; }
tip.classList.remove('hidden');
requestAnimationFrame(function () {
tip.classList.remove('opacity-0', 'scale-95');
});
document.addEventListener('pointerdown', onOutside, true);
document.addEventListener('keydown', onKeydown, true);
} else {
tip.classList.add('opacity-0', 'scale-95');
hideTimer = window.setTimeout(function () { tip.classList.add('hidden'); }, 160);
document.removeEventListener('pointerdown', onOutside, true);
document.removeEventListener('keydown', onKeydown, true);
}
}
function onOutside(e) {
if (!root.contains(e.target)) setOpen(false);
}
function onKeydown(e) {
if (e.key === 'Escape') {
setOpen(false);
trigger.focus();
}
}
trigger.addEventListener('click', function () { setOpen(!open); });
closeBtn.addEventListener('click', function () { setOpen(false); });
skipBtn.addEventListener('click', function () { current = 0; setOpen(false); });
nextBtn.addEventListener('click', function () {
if (current < STEPS.length - 1) {
current += 1;
renderStep();
} else {
current = 0;
setOpen(false);
}
});
})();
</script>
</div> # Hotspot Tooltip
Hotspot-triggered tooltip.
## Usage
```bash
npx devsnips add Tailwind/Components/Tooltips/hotspot-tooltip
```
Copy from `code.html`.
## File Structure
`code.html` · `preview.html` · `metadata.json` · `README.md` 174 lines UTF-8 · LF · Spaces: 2
DevSnips AI ready Claude · Cursor · Windsurf
Agent skill & Model Context Protocol
Pass this component straight into your AI workflow. DevSnips exposes each resource as a structured, addressable registry entry, so your agent installs the real files instead of approximating them.
devsnips://components/tooltips/hotspot-tooltip I want to use this DevSnips resource in production: Page: https://devsnips.site/library/tailwind/components/tooltips/hotspot-tooltip/ Install: npx devsnips add Tailwind/Components/Tooltips/hotspot-tooltip This is the Hotspot Tooltip — Onboarding hotspot beacon that opens a multi-step guided tour tooltip. Click the pulsing beacon to start; Next/Done walk the steps, Skip or Escape dismiss it. Use this DevSnips resource as the starting point for my project. Adapt it to my project's stack and conventions, fix any issues, and make it production-ready while preserving its intended design and behavior.
Paste into ChatGPT, Claude or your agent — it already carries the page URL and the exact install path.
Resource URI
devsnips://components/tooltips/hotspot-tooltip