Navigation✨ Premium

Guided Tour Spotlight

Tooltip dynamically anchored to each UI element, auto-flipped arrow and CSS spotlight — step-by-step user onboarding with no external library.

JSTourAnchor

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Navigation has 36 effects, including 4 free. Explore the category →

3 usage examples

SaaS Onboarding — Main Navigation Discovery — Guided Tour Spotlight example 1

① SaaS Onboarding — Main Navigation Discovery

WhenThe user logs in for the first time and doesn't know where to find their profile, messages, or settings.
WhyThe CSS spotlight isolates each element without hiding the rest of the navigation: users see the full interface context during the tour, which anchors learning better than full-screen overlays.
Settings3 steps, 200 px tooltip, indigo accent (#6366f1), 3 px ring + 30 px glow, 0.3 s transition, auto-flip arrow active.
Analytics Dashboard — Key Metric Walkthrough — Guided Tour Spotlight example 2

② Analytics Dashboard — Key Metric Walkthrough

WhenA new admin opens their dashboard for the first time and needs to understand what each KPI card represents.
WhyThe guided tour sequences the information: users learn each KPI's purpose before cross-referencing them, reducing the feeling of being overwhelmed by a dense dashboard.
Settings3 steps on metric cards, 200 px tooltip, final button labeled 'Finish', arrow-left by default (KPIs positioned left of the tooltip).
Interactive Docs — Live Tutorial in a Code Editor — Guided Tour Spotlight example 3

③ Interactive Docs — Live Tutorial in a Code Editor

WhenA developer integrates a library for the first time and explores the documentation's embedded IDE playground: file explorer icon, active file tab, and Run button.
WhyThe spotlight isolates three functional IDE zones in sequence without any overlay — the code stays fully visible throughout. The Run button, anchored at the top-right of the scene, naturally triggers the arrow's horizontal auto-flip, showcasing that mechanism in a realistic context.
Settings3 steps across 3 IDE zones (explorer icon, active file tab, top-right Run button), 200 px tooltip, indigo accent (#6366f1), 3 px ring + 30 px glow, auto-flip active on step 3, final button labeled 'Run'.

How it works

The spotlight is pure CSS: the .tour-active class applies a two-layer box-shadow to the target element — a 3 px indigo ring (rgba(99,102,241,.25) 0 0 0 3px) and a 30 px diffuse glow (rgba(99,102,241,.15) 0 0 30px). No semi-transparent overlay, no SVG mask: the highlight is a border effect that leaves the page's z-index and flow entirely untouched. The transition: .3s on .tour-element smoothly animates between highlighted elements.

The tooltip is positioned on every step by showStep(t) via two getBoundingClientRect() calls — one on the active element, one on the .tour-scene container. Coordinates are computed in pixels relative to the container: r = element.right − scene.left + 14 (horizontal offset) and l = element.top − scene.top − 10 (vertical alignment). Assigning directly to tooltip.style.left and tooltip.style.top repositions the tooltip without a full page reflow.

An auto-flip mechanism detects overflow before each render: if r + 210 > scene.width, the tooltip switches to the left side of the element (r = element.left − scene.left − 214) and the arrow is re-oriented via style.cssText — 135° rotation with a right anchor. As soon as space is sufficient on the right, the arrow-left class is restored and the arrow points back toward the highlighted element.

The tooltip's appearance relies on a two-part CSS transition on .tour-tooltip.visible: opacity 0→1 and translateY(6px→0) over 0.3 s. The visible class is added on each showStep call. The step text (.tour-text) and progress label (.tour-step, format “Step N/3”) are updated by direct textContent assignment — no DOM nodes are created per step.

Accessibility

  • prefers-reduced-motion not handled — CSS transitions (opacity, transform, border on .tour-element) remain active regardless of system settings. Recommended fix: @media (prefers-reduced-motion: reduce) { .tour-element, .tour-tooltip { transition: none !important; } }
  • The Next and Skip buttons are real <button> elements — keyboard-accessible (Tab + Enter/Space) and correctly announced by screen readers without extra code.
  • No aria-live on the tooltip: screen readers don't automatically announce step changes. Recommendation: add aria-live="polite" on .tour-text.
  • Text contrast: white (#e0e7ff) on gradient background #312e81 → ratio ≈ 6.3:1, WCAG AA compliant. The progress label (#818cf8) on #312e81 → ratio ≈ 2.8:1, below WCAG AA for normal text — reinforce if strict accessibility is required.
  • No role or aria-label on the tour container. Recommended: role="dialog" and aria-label="Guided tour" on .tour-scene, plus aria-modal="true" if the tour blocks interaction with the rest of the page.

Browser compatibility

Relies only on getBoundingClientRect(), classList.toggle(), and CSS transitions — no experimental APIs, no external dependencies.

Chrome 80+✓ Full
Firefox 75+✓ Full
Safari 13+✓ Full
Edge 80+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full

Without JavaScript, the tooltip remains hidden (<code>opacity: 0</code>) and no element receives <code>.tour-active</code> — the underlying UI stays fully functional with no console errors.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="tour-scene" id="tourScene">
  <div class="tour-ui">
    <div class="tour-element tour-active" id="tourEl1">Element 1</div>
    <div class="tour-element" id="tourEl2">Element 2</div>
    <div class="tour-element" id="tourEl3">Element 3</div>
  </div>
  <div class="tour-tooltip" id="tourTooltip">
    <div class="tour-arrow arrow-left"></div>
    <div class="tour-step" id="tourStepLabel">Step 1/3</div>
    <div class="tour-text" id="tourStepText">Step description.</div>
    <div class="tour-nav">
      <button class="tour-skip" id="tourSkip">Skip</button>
      <button class="tour-next" id="tourNext">Next</button>
    </div>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
elements (JS array) Array of DOM nodes to highlight in turn. Example: [document.getElementById('step1'), document.getElementById('step2')]. Any node inside .tour-scene is accepted — buttons, cards, form fields, nav items.
steps (JS array) Array of objects { text: '…' }, one per step. The text field populates #tourStepText. Note: the progress label and the final button condition are hardcoded for 3 steps in showStep — update "Étape " + (t+1) + "/3" and 2 === t if your tour has a different number of steps.
.tour-tooltip { width } 200px Tooltip width. Increase to 240–260 px for longer step texts; also adjust the auto-flip threshold in showStep (r + 210 > o.width → replace 210 with your-width + 10).
.tour-element.tour-active { border-color } #6366f1 Spotlight color. Replace with your brand color; also update box-shadow, the tooltip background, and the Next button color for a consistent theme.
.tour-element.tour-active { box-shadow } rgba(99,102,241,.25) 0 0 0 3px, rgba(99,102,241,.15) 0 0 30px Halo intensity. Increase the radius (30px→50px) for a more dramatic spotlight, reduce opacities for a subtle effect on a dense UI.
.tour-tooltip { background } linear-gradient(135deg, #312e81, #1e1b4b) Tooltip background. Replace with a flat color or brand gradient. Verify #e0e7ff text contrast on your new background before shipping.
.tour-nav .tour-next { background } #6366f1 Next/Finish button color. Match it with the active element's border-color. The hover color (.tour-next:hover { background: #818cf8 }) should be updated in parallel.

FAQ

Yes, 100% vanilla: getBoundingClientRect(), classList.toggle(), and pure CSS transitions. Zero npm dependencies. Compatible with Angular, React, Vue, and Svelte — wrap the logic in a component or service; the effect only touches the DOM nodes you pass in elements.
The delivered version uses global variables (scene, tooltip, elements, steps). For multiple concurrent instances, wrap each tour in a factory function (IIFE or closure) that declares its own local copies of all those variables and showStep — no CSS changes required, the classes are shared.
The horizontal auto-flip recalculates on each showStep call: if r + 210 > scene.width, the tooltip switches to the left. On very narrow screens (≤360 px), reduce width to 160–180 px in CSS and update the threshold to r + 170 > o.width in showStep. Elements at the far right of the scene trigger the left flip automatically.