react-tourlight

Single-Element Highlights

Highlight individual elements for "what's new" callouts and feature announcements without a full tour.

Sometimes you don't need a multi-step tour. You just want to draw attention to a single element -- a new feature, a changed button, or an important action. react-tourlight provides two ways to do this.

SpotlightHighlight component

<SpotlightHighlight> is a declarative component for one-off highlights. It shows a spotlight and tooltip around a single element:

import { useState } from 'react'
import { SpotlightHighlight } from 'react-tourlight'

function Dashboard() {
  const [showHighlight, setShowHighlight] = useState(true)

  return (
    <>
      <SpotlightHighlight
        target="#new-feature"
        title="New: Dark Mode"
        content="We just shipped dark mode. Try it out!"
        active={showHighlight}
        placement="bottom"
        onDismiss={() => setShowHighlight(false)}
      />
      <button id="new-feature">Toggle Theme</button>
    </>
  )
}

Props

PropTypeDefaultDescription
targetstring | RefObject<HTMLElement>--CSS selector or React ref for the target element
titlestring--Tooltip title
contentReactNode--Tooltip content
activebooleantrueWhether the highlight is currently visible
placementPlacement'auto'Tooltip placement relative to target
spotlightPaddingnumber--Padding around the spotlight cutout (px)
spotlightRadiusnumber--Border radius of the spotlight cutout (px)
onDismiss() => void--Called when the highlight is dismissed

The highlight is automatically cleaned up when the component unmounts or when active is set to false.

useSpotlightControl hook

For imperative control, use useSpotlightControl(). This is useful when you need to trigger highlights from event handlers or effects:

import { useSpotlightControl } from 'react-tourlight'

function FeatureAnnouncement() {
  const spotlight = useSpotlightControl()

  const showAnnouncement = () => {
    spotlight.highlight({
      target: '#export-button',
      title: 'New: CSV Export',
      content: 'You can now export your data as CSV.',
      placement: 'bottom',
    })
  }

  return <button onClick={showAnnouncement}>Show Announcement</button>
}

Dismiss the highlight programmatically with spotlight.dismissHighlight().

SpotlightControl API

MethodTypeDescription
highlight(step: SpotlightStep) => voidShow a spotlight on a single element
dismissHighlight() => voidDismiss the active highlight
start(tourId: string) => voidStart a registered tour
stop() => voidStop the active tour
next() => voidGo to the next step
previous() => voidGo to the previous step
skip() => voidSkip the current tour
goToStep(index: number) => voidJump to a specific step
isActivebooleanWhether a tour or highlight is active

"What's new" callout pattern

A common use case is showing a highlight once when a user first encounters a new feature. Combine SpotlightHighlight with localStorage to show it only once:

import { useState, useEffect } from 'react'
import { SpotlightHighlight } from 'react-tourlight'

function NewFeatureCallout() {
  const [show, setShow] = useState(false)

  useEffect(() => {
    const dismissed = localStorage.getItem('dismissed-export-callout')
    if (!dismissed) {
      setShow(true)
    }
  }, [])

  const handleDismiss = () => {
    setShow(false)
    localStorage.setItem('dismissed-export-callout', 'true')
  }

  return (
    <SpotlightHighlight
      target="#export-button"
      title="New: CSV Export"
      content="Export your data as CSV with one click."
      active={show}
      placement="bottom"
      onDismiss={handleDismiss}
    />
  )
}

Dismissing highlights

Highlights can be dismissed in several ways:

  • Pressing Escape (if escToDismiss is enabled on the provider, which it is by default)
  • Clicking the overlay (if overlayClickToDismiss is enabled, which it is by default)
  • Clicking the close button on the tooltip
  • Programmatically via dismissHighlight() from useSpotlightControl
  • Setting active={false} on SpotlightHighlight

When a highlight is dismissed by the user (Escape, overlay click, or close button), the onDismiss callback is called, allowing you to update your state accordingly.