Source Code

<div class="pt-demo" id="ptDemo">
  <header class="pt-topbar">
    <div class="pt-logo">Northstar</div>
    <nav class="pt-nav">
      <button class="pt-nav-item" id="ptTarget0">Dashboard</button>
      <button class="pt-nav-item" id="ptTarget1">Projects</button>
      <button class="pt-nav-item" id="ptTarget2">Reports</button>
    </nav>
    <button class="pt-avatar" id="ptTarget3">JS</button>
  </header>

  <main class="pt-main">
    <div class="pt-card" id="ptTarget4">
      <h3>Create your first project</h3>
      <p>Projects group your tasks, files, and teammates in one place.</p>
      <button class="pt-card-btn">New project</button>
    </div>
    <div class="pt-panel">
      <p>Everything else on the page fades out while the tour is active, keeping attention on one element at a time.</p>
      <button class="pt-restart-btn" id="ptRestartBtn">Restart tour</button>
    </div>
  </main>

  <div class="pt-overlay" id="ptOverlay" hidden></div>
  <div class="pt-tooltip" id="ptTooltip" hidden>
    <div class="pt-tooltip-step" id="ptStepLabel">Step 1 of 4</div>
    <h4 class="pt-tooltip-title" id="ptTooltipTitle"></h4>
    <p class="pt-tooltip-text" id="ptTooltipText"></p>
    <div class="pt-tooltip-footer">
      <a href="#" class="pt-skip" id="ptSkip">Skip tour</a>
      <div class="pt-tooltip-btns">
        <button class="pt-btn pt-btn-ghost" id="ptBack">Back</button>
        <button class="pt-btn pt-btn-primary" id="ptNext">Next</button>
      </div>
    </div>
  </div>
</div>

Product Tour Spotlight Overlay — Free HTML CSS JS Snippet

Product Tour Spotlight Overlay · Modals · Plain HTML, CSS & JS · Live preview

What's included

Features

Spotlight cutout built from a single element using the oversized box-shadow trick, no clip-path masking required
Step positions computed live from getBoundingClientRect() on real target elements, not hardcoded coordinates
Smooth CSS-transitioned movement of both the spotlight and tooltip between steps
Step counter ("Step 2 of 4") and dynamic Back/Next/Finish button labeling and disabled states
Tooltip position auto-clamped to the viewport so it never renders off-screen
Skip link and Finish action both exit the tour cleanly from any step
Restart button to replay the tour without reloading the page
Recalculates spotlight position on window resize to stay aligned with its target

About this UI Snippet

Product Tour Spotlight Overlay — Guided Onboarding with a Spotlighted Cutout

Screenshot of the Product Tour Spotlight Overlay snippet rendered live

This snippet builds the "spotlight tour" pattern used by countless onboarding flows: a dark, semi-transparent layer covers the whole page except for a rectangular cutout around the element currently being explained, paired with a floating tooltip card that carries the step's copy and navigation controls.

The spotlight cutout

The cutout is produced with a single element, .pt-overlay, whose box-shadow is set to 0 0 0 9999px rgba(15,23,42,0.6). Because the element itself has a transparent background, only its shadow — spread out to cover the entire viewport — is visible, so the element's own bounding box reads as a clear "hole" in the dark layer. Positioning the overlay directly on top of the target element (via getBoundingClientRect()) is what makes the hole line up with whatever is being highlighted.

Driving position from real layout data

TOUR_STEPS is a plain array mapping each step to a target element's id. positionTour() reads that target's live getBoundingClientRect() on every step change and writes the resulting top/left/width/height directly onto the overlay and tooltip, with a small CSS transition so the spotlight visibly glides between elements rather than jumping.

Tooltip placement and viewport clamping

The tooltip defaults to appearing just below the target, but its left offset and vertical placement are clamped against window.innerWidth/innerHeight so it never renders off-screen for targets near an edge — flipping above the target when there isn't room below.

Step navigation and exit paths

Next/Back simply increment or decrement currentStep and re-run positionTour(); the Back button disables itself on step one, and Next relabels itself "Finish" on the last step. A Skip link and the Finish action both hide the overlay and tooltip immediately, and a Restart button lets the demo be replayed without a page reload.

Step by step

How to Use

  1. 1
    Load the snippetClick "Product Tour Spotlight Overlay" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
  2. 2
    Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
  3. 3
    Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
  4. 4
    Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
  5. 5
    Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.

Real-world uses

Common Use Cases

New user onboarding
Walk first-time users through the key parts of a dashboard or app on their very first visit.
Feature announcements
Point returning users at a newly shipped feature with a focused, single-element spotlight.
In-app documentation
Replace static help articles with a live, contextual walkthrough of the actual interface.
Reference for spotlight overlays
A reusable base for any UI that needs to dim the page while highlighting one specific element.

Got questions?

Frequently Asked Questions

The overlay element is transparent itself but has an oversized box-shadow (0 0 0 9999px) that fills the rest of the viewport. Positioning that transparent element over the target creates the visual effect of a hole in the dark layer.

Each step in TOUR_STEPS references a target element by id. positionTour() calls getBoundingClientRect() on that live DOM element every time the step changes, so positioning always reflects the actual current layout.

positionTour() clamps the computed left offset against window.innerWidth and flips the tooltip above the target if there is not enough room below it, keeping it fully visible at any target position.

Yes — add entries to the TOUR_STEPS array with a targetId matching any element in the page, plus a title and text; the existing navigation logic works with any number of steps.