Troubleshooting
Diagnose and fix common User Tour Kit issues: missing targets, positioning glitches, hydration errors, and focus trap problems
Troubleshooting
Solutions to common issues when using User Tour Kit.
Tour Not Starting
Symptoms
- Calling
start()does nothing - Tour never appears
Solutions
1. Check provider setup
Ensure your app is wrapped with the required providers:
// Correct setup
<TourKitProvider>
<TourProvider tours={[myTour]}>
<App />
</TourProvider>
</TourKitProvider>2. Verify tour ID matches
The tour ID passed to start() must match the tour definition:
const myTour = createTour({ id: 'welcome', ... })
// Correct
start('welcome')
// Wrong - ID mismatch
start('my-tour')3. Check if tour was already completed
Tours are skipped if previously completed. Clear persisted state:
const { reset } = useTour()
reset() // Clears completion statusTarget Element Not Found
Symptoms
- Tour starts but step doesn't show
- Console error: "Target element not found"
Solutions
1. Verify selector
Check the CSS selector is correct:
// Check element exists
document.querySelector('#my-button') // Should not be null
// Use in step
createStep({ target: '#my-button', ... })2. Wait for dynamic content
For dynamically loaded elements:
createStep({
target: '#dynamic-element',
waitForTarget: true,
waitForTargetTimeout: 5000, // Wait up to 5 seconds
})3. Check element visibility
Hidden elements (display: none) cannot be targeted. Ensure element is visible.
Tooltip Positioned Incorrectly
Symptoms
- Tooltip appears in wrong position
- Tooltip is cut off by viewport edge
- Tooltip jumps around
Solutions
1. Check z-index conflicts
Tour elements need high z-index. Override if needed:
:root {
--tour-z-overlay: 10000;
--tour-z-card: 10001;
}2. Handle scrollable containers
If target is inside a scrollable container:
// Scroll target into view first
createStep({
target: '#nested-element',
scrollIntoView: true,
})3. Try different placement
createStep({
target: '#element',
placement: 'top', // Try: top, bottom, left, right
})Keyboard Navigation Not Working
Symptoms
- Arrow keys don't navigate
- Escape doesn't close tour
Solutions
1. Check keyboard config
<TourProvider
tours={tours}
keyboard={{
enabled: true, // Must be true
nextKeys: ['ArrowRight', 'Enter'],
prevKeys: ['ArrowLeft'],
exitKeys: ['Escape'],
}}
/>2. Check focus
Keyboard events require focus on tour card. Check focus trap:
createStep({
focusTrap: true, // Enable focus trap
})3. Input field interference
Keyboard navigation is disabled when typing in input fields (by design).
SSR Hydration Errors
Symptoms
- "Text content does not match server-rendered HTML"
- "Hydration failed because the initial UI does not match"
Solutions
1. Use 'use client' directive
Tour components must be client components:
'use client'
import { Tour, TourStep } from '@tour-kit/react'2. Defer tour rendering
Use dynamic import with ssr: false:
import dynamic from 'next/dynamic'
const Tour = dynamic(
() => import('@tour-kit/react').then(m => m.Tour),
{ ssr: false }
)3. Check for server-only code
Don't access window or document during SSR.
Portal Issues
Symptoms
- Tour card not visible
- Overlay covers entire page including card
Solutions
1. Check portal container
Ensure <body> exists and isn't display: none:
// Portal renders to document.body by default2. Z-index stacking
Adjust CSS variables:
:root {
--tour-z-overlay: 9998;
--tour-z-card: 9999;
}Multi-Page Tour Issues
Symptoms
- Tour doesn't continue after navigation
- State lost between pages
Solutions
1. Configure router adapter
import { useNextAppRouter } from '@tour-kit/react'
const router = useNextAppRouter()
<TourProvider tours={tours} router={router}>2. Enable persistence
<TourKitProvider
persistence={{
enabled: true,
storage: 'localStorage',
}}
>3. Verify route patterns
createStep({
route: '/dashboard', // Exact match
routeMatchMode: 'exact', // or 'startsWith'
})Performance Issues
Symptoms
- Laggy animations
- High CPU usage
- Slow step transitions
Solutions
1. Reduce motion
Respect user preferences:
<TourKitProvider
accessibility={{
reduceMotion: 'system', // Respects prefers-reduced-motion
}}
>2. Optimize step content
Avoid heavy components in step content:
// Avoid
createStep({
content: <HeavyComponent />, // Re-renders on every update
})
// Better
createStep({
content: { title: 'Simple', description: 'Text only' },
})3. Limit spotlight updates
Use debounced position updates for moving targets.
Styling Not Applied
Symptoms
- Tour looks unstyled
- CSS variables not working
Solutions
1. Import CSS
import '@tour-kit/react/styles.css'2. Tailwind config
Add User Tour Kit to content paths:
module.exports = {
content: [
'./node_modules/@tour-kit/react/**/*.{js,ts,jsx,tsx}',
// Your paths...
],
}3. CSS variable scope
Define variables at root level:
:root {
--tour-primary: #6366f1;
--tour-radius: 8px;
}FAQ
Can I have multiple tours active at once?
No, only one tour can be active at a time. This is by design for UX consistency.
How do I skip specific steps conditionally?
Use the when callback:
createStep({
id: 'admin-only',
when: () => user.isAdmin, // Only show for admins
})Can I use User Tour Kit with React Native?
No, User Tour Kit is designed for web only. It uses DOM APIs extensively.
How do I track tour analytics?
Use the analytics package:
import { AnalyticsProvider } from '@tour-kit/analytics'
<AnalyticsProvider plugins={[myPlugin]}>Is User Tour Kit accessible?
Yes! User Tour Kit is WCAG 2.1 AA compliant with:
- Full keyboard navigation
- Focus trapping
- Screen reader announcements
- Reduced motion support
How do I style tours differently per-step?
Use step-specific class names:
createStep({
className: 'my-special-step',
content: { ... },
})Can tours span iframe content?
No, User Tour Kit cannot target elements inside iframes due to browser security restrictions.
Still having issues? Open an issue on GitHub.