Skip to content

FRD-062: Feature Spotlight Tooltip Widget

FieldValue
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
Target Releasev2.0.0 (P2)
T-Shirt SizeM
TypeWidget

Document Summary

A sequential coach-mark system that spotlights UI elements one at a time with a tooltip overlay, dimmed backdrop, and navigation controls. Used for feature onboarding, product tours, and contextual help. Supports dismiss, skip-all, and persistence of completion state via callbacks.


Introduction

Overview

Product tours and feature spotlights are a standard onboarding pattern for SaaS applications. This widget provides a step-by-step coach-mark system that highlights target elements, displays contextual tooltips, and tracks completion state through consumer-provided callbacks.

Goals

  • Sequential spotlight steps targeting DOM elements by ref or CSS selector.
  • Tooltip with title, body, step counter, and navigation (back/next/skip/done).
  • Dimmed backdrop with a cutout around the spotlighted element.
  • Scroll-into-view for off-screen targets.
  • Persistence of completion/dismissal via onComplete and onDismiss callbacks.
  • Ship Storybook stories demonstrating multi-step tours.

Non-Goals

  • Built-in persistence layer (localStorage, cookies, or API).
  • Analytics event tracking (consumer instruments via callbacks).
  • Video or animated content inside tooltips.
  • Branching/conditional step logic.

Scope

In Scope

ItemDescription
FeatureSpotlight componentOrchestrates the tour: backdrop, cutout, tooltip positioning
SpotlightStep typeData shape for each step (target, title, body, placement)
Backdrop overlaySemi-transparent overlay with cutout around the target element
TooltipPositioned tooltip with step content and navigation controls
NavigationBack, Next, Skip All, and Done buttons
Scroll behaviorAuto-scrolls target into view when advancing steps
Storybook storiesThreeStepTour, SingleStep, SkipAll, DismissAndResume

Out of Scope

ItemRationale
PersistenceConsumer decides storage mechanism
Conditional stepsAdds complexity; can filter steps array externally
Inline/embedded modeFocus on overlay spotlight; inline tips are a separate pattern

Users and Pain Points

UserPain Point
Product managersNo reusable onboarding tour component; teams build ad-hoc solutions
DevelopersPositioning logic and backdrop cutouts are error-prone to implement
End usersMissing contextual guidance for new features

Definitions

TermDefinition
Coach markA UI overlay that highlights a specific element with explanatory content
SpotlightThe visual cutout in the backdrop that draws attention to the target
TourA sequence of spotlight steps presented in order
PersistenceRemembering that a user has completed or dismissed a tour

Current State

No spotlight or coach-mark component exists in the design system. The Tooltip primitive exists for hover tooltips but does not support sequential tours, backdrops, or step navigation.


Proposed Solution

Create a FeatureSpotlight widget at src/components/widgets/feature-spotlight.tsx that:

  1. Accepts an array of SpotlightStep objects defining targets, content, and placement.
  2. Renders a full-viewport backdrop with a CSS/SVG cutout around the current target.
  3. Positions a tooltip adjacent to the cutout using Floating UI (or manual calculation).
  4. Provides Back, Next, Skip All, and Done navigation.
  5. Scrolls off-screen targets into view before showing the spotlight.
  6. Fires onStepChange, onComplete, and onDismiss callbacks for consumer instrumentation and persistence.

Requirements

The spotlight must handle dynamic layouts (targets may move on resize), clean up on unmount, and not interfere with the target element’s interactivity when the spotlight is active.


Functional Requirements

IDRequirementPriority
FR-01Render a semi-transparent backdrop with a cutout around the target elementMust
FR-02Display a tooltip with title, body text, and step counter (e.g., “2 of 5”)Must
FR-03Position tooltip relative to target using configurable placement (top/bottom/left/right)Must
FR-04Provide Next and Back navigation buttonsMust
FR-05Provide a Skip All button to dismiss the entire tourMust
FR-06Show a Done button on the final stepMust
FR-07Scroll the target element into view when it is off-screenMust
FR-08Call onStepChange(stepIndex) when the active step changesMust
FR-09Call onComplete() when the user finishes the tourMust
FR-10Call onDismiss(stepIndex) when the user skips or closes the tourMust
FR-11Update cutout position on window resize and scrollShould
FR-12Allow the target element to remain interactive (clickable) during spotlightShould

Non-Functional Requirements

IDRequirement
NFR-01Backdrop renders without causing layout reflow
NFR-02Cutout repositions within 100 ms of resize/scroll events
NFR-03Full light/dark theme support for the tooltip
NFR-04Bundle size under 4 KB gzipped

API / Interface Requirements

interface SpotlightStep {
target: string | React.RefObject<HTMLElement>; // CSS selector or ref
title: string;
body?: string | ReactNode;
placement?: "top" | "bottom" | "left" | "right"; // default "bottom"
spotlightPadding?: number; // pixels around target cutout; default 8
}
interface FeatureSpotlightProps {
steps: SpotlightStep[];
active?: boolean; // default true
initialStep?: number; // default 0
onStepChange?: (index: number) => void;
onComplete?: () => void;
onDismiss?: (stepIndex: number) => void;
backdropOpacity?: number; // default 0.5
skipLabel?: string; // default "Skip tour"
nextLabel?: string; // default "Next"
backLabel?: string; // default "Back"
doneLabel?: string; // default "Done"
}

Accessibility Requirements

IDRequirement
A11Y-01Tooltip has role="dialog" with aria-label describing the tour step
A11Y-02Focus moves to the tooltip when a new step activates
A11Y-03Escape key dismisses the tour (calls onDismiss)
A11Y-04Navigation buttons are keyboard-accessible
A11Y-05Step counter is announced to screen readers
A11Y-06Backdrop does not trap focus away from the tooltip and target

Content and Documentation Requirements

  • Storybook doc page with usage, props, and integration patterns.
  • Stories: ThreeStepTour, SingleStep, SkipAll, CustomPlacement, DarkMode.
  • Guidance on persistence patterns (localStorage example in docs).
  • JSDoc on all exported types.

Dependencies

DependencyTypeNotes
Floating UI or manual positioningExternal/InternalTooltip placement relative to target
ButtonInternalNavigation controls
PortalInternal/ReactRender backdrop at document root

Risks and Tradeoffs

RiskImpactMitigation
Target element not in DOM when tour startsSpotlight renders incorrectlyValidate target existence; skip step with console warning
Dynamic layouts shift targetsCutout misalignedRecalculate on resize/scroll with throttled observer
Z-index conflictsBackdrop hidden behind modalsUse a high z-index (configurable) and document layering guidance

Open Questions

  1. Should the widget support hotspot-only mode (no sequential navigation)?
  2. Do we need support for tooltip media (images, GIFs) inside steps?
  3. Should the target element receive a temporary highlight ring in addition to the cutout?

Acceptance Criteria

  • Backdrop renders with a cutout around the target element.
  • Tooltip displays step content with correct placement.
  • Navigation (Back, Next, Skip, Done) works correctly.
  • Off-screen targets scroll into view.
  • onStepChange, onComplete, and onDismiss callbacks fire at correct times.
  • Escape key dismisses the tour.
  • All Storybook stories render without errors.
  • Passes axe accessibility audit with zero violations.
  • Unit tests cover step navigation, skip, complete, and dismiss flows.

LLM Handoff Instructions

When implementing this FRD:

  1. Create src/components/widgets/feature-spotlight.tsx.
  2. Use a Portal to render the backdrop overlay at the document root.
  3. Calculate target bounding rect for cutout positioning; use ResizeObserver and scroll listeners to keep it updated.
  4. Use CSS clip-path or an SVG mask for the backdrop cutout.
  5. Create src/components/widgets/feature-spotlight.stories.tsx. For stories, use mock target elements within a Storybook decorator.
  6. Create src/components/widgets/feature-spotlight.test.tsx.
  7. Use scrollIntoView({ behavior: "smooth", block: "center" }) for off-screen targets.

Decision Log

DateDecisionRationale
2026-05-26Target via CSS selector or refSelector is convenient for quick tours; ref is type-safe for component-owned elements
2026-05-26No built-in persistencePersistence mechanisms vary (localStorage, API, cookie); consumer decides

Document History

DateVersionAuthorChanges
2026-05-260.1David HolmesInitial draft