Troubleshooting & FAQ
Common issues, browser compatibility, and frequently asked questions.
Common issues
Spotlight doesn't appear
-
Missing CSS import — Make sure you import the stylesheet:
import 'react-tourlight/styles.css' -
Tour not started —
<SpotlightTour>only registers steps. You need to callstart():const { start } = useSpotlight() start('your-tour-id') -
Target element not found — Verify the CSS selector or ref points to a mounted element. Open DevTools and run
document.querySelector('#your-selector')to confirm. -
Missing Provider — Ensure
<SpotlightProvider>wraps both your<SpotlightTour>and the component callinguseSpotlight().
Tooltip is mispositioned
-
Install Floating UI — Without
@floating-ui/react-dom, positioning falls back to a basic algorithm. Install the optional peer dependency:npm install @floating-ui/react-dom -
Target inside a scroll container — Floating UI handles this automatically, but the basic fallback may not. Ensure the target element is visible in the viewport.
-
CSS transforms on ancestors — CSS
transformon a parent element creates a new containing block, which can offset fixed positioning. This is a browser behavior, not a bug. Floating UI handles this correctly.
Tour doesn't advance
-
Async elements — If the next step's target isn't in the DOM yet, react-tourlight waits for it using
MutationObserver. Ensure the element eventually mounts. Check thewhencallback if you're using conditional steps. -
Focus trap interference — If another focus trap (e.g., a modal) is active, it may conflict with the spotlight's focus trap. Dismiss the modal before starting the tour.
SSR / hydration issues
react-tourlight is client-only. The overlay and tooltip render via portals and depend on document. In Next.js or other SSR frameworks:
// Dynamically import if needed
import dynamic from 'next/dynamic'
const SpotlightProvider = dynamic(
() => import('react-tourlight').then(m => m.SpotlightProvider),
{ ssr: false }
)Or simply ensure start() is only called after hydration (e.g., in a useEffect), which is the normal pattern.
Browser compatibility
| Browser | Minimum version | Notes |
|---|---|---|
| Chrome | 88+ | Full support |
| Firefox | 97+ | Full support |
| Safari | 15.4+ | Full support |
| Edge | 88+ | Full support (Chromium-based) |
| iOS Safari | 15.4+ | Full support |
| Chrome Android | 88+ | Full support |
react-tourlight uses:
- CSS
clip-path: path()(widely supported) MutationObserver(supported everywhere)inertattribute (Chrome 102+, Firefox 112+, Safari 15.5+)
For older browsers without inert support, the accessibility features degrade gracefully — keyboard navigation and ARIA attributes still work, but background content won't be fully inert.
FAQ
Does it work with React Native?
No. react-tourlight is for React DOM (web) only. It relies on DOM APIs like getBoundingClientRect, CSS clip-path, and portal rendering.
Can I use it without Floating UI?
Yes. @floating-ui/react-dom is an optional peer dependency. Without it, tooltip positioning uses a basic algorithm that places the tooltip adjacent to the target element. For most cases this works fine, but you lose smart flip/shift behavior when the tooltip would overflow the viewport.
Does it support multiple simultaneous tours?
Only one tour can be active at a time. You can register multiple tours with different IDs and start them independently, but starting a new tour will stop the current one.
Can I persist tour completion state?
react-tourlight doesn't handle persistence — that's your app's concern. Use the onComplete callback to save state:
<SpotlightTour
id="onboarding"
steps={steps}
onComplete={() => localStorage.setItem('onboarding-done', 'true')}
/>Does it work with CSS-in-JS libraries?
Yes. The default styles are in a regular CSS file (react-tourlight/styles.css). You can override styles via CSS custom properties, the theme prop, or the renderTooltip render prop for full control.
What's the bundle size?
The core library is ~5KB gzipped with zero runtime dependencies. If you add @floating-ui/react-dom, that adds ~4KB gzipped.