react-walkthrough-screens
v2.3.0
Published
A production-ready, zero-dependency React walkthrough and product tour component. Spotlight highlighting, step-by-step tooltips, smooth animations, full TypeScript support, auto-injected CSS, Vite and Tauri compatible.
Downloads
1,301
Maintainers
Readme
react-walkthrough-screens
A production-ready, zero-dependency React product tour and walkthrough component with spotlight highlighting, step-by-step tooltips, smooth animations, and full TypeScript support.
Contents
- Features
- Installation
- Quick Start
- TypeScript
- API Reference
- Recipes
- Browser Support
- Changelog
- Contributing
- License
✨ Features
| | |
|---|---|
| 🔦 Spotlight | Isolates any DOM element with a focused, animated cutout |
| 🧩 Zero dependencies | No bloat — only React & ReactDOM as peer deps |
| 🎨 Fully themeable | Override colors, fonts, z-index and per-button styles |
| 🌍 Localisable | Customise every button label |
| ♿ Accessible | Semantic HTML, keyboard-ready navigation |
| 📦 Auto-injected CSS | No stylesheet import required — styles inject themselves |
| 🟦 TypeScript | Full .d.ts declarations shipped in the package |
| 📱 Responsive | Adapts cleanly to mobile viewports |
| ⚡ Tiny | < 18 kB minified + gzipped |
| ⚙️ ESM + CJS | Works in Vite, Webpack, Tauri, Next.js, and CRA |
Installation
# npm
npm install react-walkthrough-screens
# yarn
yarn add react-walkthrough-screens
# pnpm
pnpm add react-walkthrough-screensPeer dependencies (must already be present in your project):
npm install react react-dom # react >=16.8, react-dom >=16.8No CSS import is required. Styles are injected automatically into
<head>on first render.
Quick Start
import { useState } from 'react';
import Walkthrough from 'react-walkthrough-screens';
const steps = [
{
target: '#dashboard-header',
content: 'Welcome to the dashboard! This is your control centre.',
placement: 'bottom',
},
{
target: '#sidebar-nav',
content: 'Use the sidebar to navigate between sections.',
placement: 'right',
},
{
target: '#create-btn',
content: 'Click here to create your first project.',
placement: 'top',
},
];
export default function App() {
const [run, setRun] = useState(false);
return (
<>
<button onClick={() => setRun(true)}>Start Tour</button>
<Walkthrough
steps={steps}
run={run}
showProgress
showSkipButton
callback={({ status }) => {
if (status === 'finished' || status === 'skipped') {
setRun(false);
}
}}
/>
</>
);
}Tip: Target elements by
id(#my-id) or any valid CSS selector (.class,[data-tour="step1"]).
TypeScript
Full type declarations are bundled. Import them as needed:
import Walkthrough from 'react-walkthrough-screens';
import type {
WalkthroughStep,
WalkthroughProps,
WalkthroughCallbackData,
WalkthroughStyles,
WalkthroughLocale,
} from 'react-walkthrough-screens';
const steps: WalkthroughStep[] = [
{ target: '#my-element', content: 'Hello!', placement: 'bottom' },
];API Reference
<Walkthrough /> Props
| Prop | Type | Default | Description |
|---|---|---|---|
| steps | WalkthroughStep[] | required | Ordered array of step descriptors |
| run | boolean | false | true starts the tour; false stops it |
| showProgress | boolean | true | Shows a "1 / 5" counter in the footer |
| showSkipButton | boolean | true | Shows a Skip button on non-final steps |
| disableOverlayClose | boolean | false | Prevents closing when the overlay is clicked |
| spotlightPadding | number | 4 | Extra space (px) around the highlighted element |
| hideBackButton | boolean | false | Hides the Back navigation button |
| scrollToFirstStep | boolean | true | Scrolls the first target into view automatically |
| styles | WalkthroughStyles | {} | Style overrides — see Styles |
| locale | WalkthroughLocale | {} | Button label overrides — see Locale |
| callback | (data: WalkthroughCallbackData) => void | () => {} | Fired on every user action |
Step Object
interface WalkthroughStep {
target: string; // Any valid CSS selector: '#id', '.class', '[data-tour]'
content: ReactNode; // Text string or full JSX
placement?: 'top' // Tooltip position relative to the target
| 'bottom' // ← default
| 'left'
| 'right'
| 'center'; // Centred on screen — no spotlight shown
}Styles
Override the visual appearance of every part of the component:
interface WalkthroughStyles {
options?: {
primaryColor?: string; // Accent / button color — default '#e91e63'
textColor?: string; // Tooltip text color — default '#333'
backgroundColor?: string; // Tooltip background — default '#fff'
overlayColor?: string; // Backdrop RGBA color — default 'rgba(0,0,0,0.5)'
zIndex?: number; // Overlay z-index — default 10000
};
tooltip?: CSSProperties; // Additional styles for the tooltip card
buttonNext?: CSSProperties; // Additional styles for Next / Finish button
buttonBack?: CSSProperties; // Additional styles for Back button
buttonSkip?: CSSProperties; // Additional styles for Skip button
}Example — custom brand color:
<Walkthrough
steps={steps}
run={run}
styles={{
options: {
primaryColor: '#0078d4',
overlayColor: 'rgba(0, 0, 0, 0.65)',
zIndex: 99999,
},
buttonNext: { borderRadius: '20px', fontWeight: '700' },
}}
callback={({ status }) => status !== 'running' && setRun(false)}
/>Locale
Override any button label (useful for i18n):
interface WalkthroughLocale {
back?: string; // Default: 'Back'
next?: string; // Default: 'Next'
last?: string; // Default: 'Finish' (shown only on the final step)
skip?: string; // Default: 'Skip'
}Example:
<Walkthrough
steps={steps}
run={run}
locale={{ next: 'Continue →', last: 'Done ✓', skip: 'Not now' }}
callback={({ status }) => status !== 'running' && setRun(false)}
/>Callback
Fired on every user interaction:
interface WalkthroughCallbackData {
status: 'running' | 'finished' | 'skipped';
action: 'next' | 'back' | 'skip' | 'close';
index: number; // Zero-based index of the current step
step: WalkthroughStep; // Reference to the current step object
}| status | When fired |
|---|---|
| 'running' | User navigated to a new step |
| 'finished' | User completed the last step |
| 'skipped' | User clicked Skip or the overlay |
| action | When fired |
|---|---|
| 'next' | Next / Finish button clicked |
| 'back' | Back button clicked |
| 'skip' | Skip button clicked |
| 'close' | Overlay clicked (only when disableOverlayClose={false}) |
Recipes
Persisting Tour State
Avoid re-running the tour on every page load:
const [run, setRun] = useState(
() => localStorage.getItem('tourCompleted') !== 'true'
);
<Walkthrough
steps={steps}
run={run}
callback={({ status }) => {
if (status === 'finished' || status === 'skipped') {
setRun(false);
localStorage.setItem('tourCompleted', 'true');
}
}}
/>Conditional Steps
Filter steps based on user roles or feature flags:
const allSteps = [
{ target: '#dashboard', content: 'Your dashboard.', placement: 'bottom' },
{ target: '#admin-panel', content: 'Admin controls.', placement: 'right' },
];
const steps = allSteps.filter((_, i) => isAdmin || i !== 1);JSX Step Content
Steps accept full JSX, not just strings:
const steps = [
{
target: '#upload-btn',
placement: 'bottom',
content: (
<div>
<strong>Upload your files</strong>
<p style={{ margin: '6px 0 0', color: '#555' }}>
Supported formats: <code>.xlsx</code>, <code>.csv</code>
</p>
</div>
),
},
];Vite / Tauri Setup
If you are using Vite (including Tauri apps), add the following to your vite.config.js to ensure the package is always pre-bundled:
// vite.config.js
export default defineConfig({
optimizeDeps: {
include: ['react-walkthrough-screens'],
},
});This prevents the Failed to resolve import error that can occur when the Vite dep cache is cold.
Browser Support
| Chrome | Firefox | Safari | Edge | Node (SSR) | |--------|---------|--------|------|------------| | ✅ 80+ | ✅ 75+ | ✅ 13+ | ✅ 80+ | ✅ (no-op) |
SSR / server-side rendering is safe — CSS injection and DOM access are guarded with
typeof documentchecks.
Changelog
v2.3.0 — 2026-04-22
- Production-ready release
- Added
"browser","module", and"default"conditions toexportsmap (fixes Vite/Tauri resolution) - Source files (
src/) now included in published package - Removed
rollup-plugin-postcssdependency — CSS is fully embedded in JS (no external stylesheet) - Improved README with recipes, Vite/Tauri guide, and full API documentation
- Enhanced TypeScript declarations with
WalkthroughStylesandWalkthroughLocaleexports
v2.2.1 — 2026-04-22
- Fixed Vite
Failed to resolve importerror by adding"default"export condition sideEffects: trueset correctly to prevent CSS tree-shaking
v2.2.0 — 2026-04-22
- CSS auto-injected into
<head>at runtime viauseEffect— no stylesheet import required - Fixed invisible overlay:
width: 100vw; height: 100vhadded to.walkthrough-overlay - Fixed
sideEffects: falsethat caused bundlers to strip CSS injection
v2.1.0 — 2026-04-20
- Added full TypeScript declarations (
.d.ts) - Added
exportsfield (ESM + CJS + types) topackage.json - Added
enginesconstraint (node >= 14) - MIT
LICENSEfile included in published package
v2.0.4 — 2026-04-19
- Close button removed from tooltip
v2.0.1 — 2026-04-19
- Initial stable release
Contributing
Issues and pull requests are welcome.
Repository: github.com/maqsoftware/react-walkthrough-screens
Bug reports: github.com/maqsoftware/react-walkthrough-screens/issues
License
A lightweight, zero-dependency React product tour and walkthrough component with spotlight highlighting, step-by-step tooltips, smooth animations, and full TypeScript support.
✨ Features
- 🔦 Spotlight — highlights any DOM element with a focused overlay
- 🪄 Zero dependencies — no bloat, no peer conflicts beyond React itself
- 🎨 Fully themeable — override colors, fonts, z-index, and per-button styles
- 🌍 Localisable — customise every button label
- ♿ Accessible — semantic HTML, keyboard-friendly navigation
- 📦 Auto-injected CSS — no separate stylesheet import required
- 🟦 TypeScript — ships with complete
.d.tstype declarations - 📱 Responsive — adapts to mobile viewports out of the box
- ⚡ Tiny — < 20 kB minified
Installation
npm install react-walkthrough-screens
# or
yarn add react-walkthrough-screensPeer dependencies (must already be installed in your project):
npm install react react-domQuick Start
import { useState } from 'react';
import Walkthrough from 'react-walkthrough-screens';
const steps = [
{
target: '.dashboard-header',
content: 'Welcome! This is your main dashboard.',
placement: 'bottom',
},
{
target: '.sidebar-nav',
content: 'Use the sidebar to navigate between sections.',
placement: 'right',
},
{
target: '.create-btn',
content: 'Click here to create your first project.',
placement: 'top',
},
];
export default function App() {
const [run, setRun] = useState(false);
return (
<>
<button onClick={() => setRun(true)}>Start Tour</button>
<Walkthrough
steps={steps}
run={run}
callback={({ status }) => {
if (status === 'finished' || status === 'skipped') {
setRun(false);
}
}}
/>
</>
);
}No CSS import needed — styles are injected automatically at runtime.
TypeScript
This package ships with full TypeScript declarations. Import the types as needed:
import Walkthrough, {
WalkthroughStep,
WalkthroughProps,
WalkthroughCallbackData,
} from 'react-walkthrough-screens';
const steps: WalkthroughStep[] = [
{ target: '.my-element', content: 'Hello!', placement: 'bottom' },
];API Reference
<Walkthrough /> Props
| Prop | Type | Default | Description |
|---|---|---|---|
| steps | WalkthroughStep[] | [] | Ordered array of step descriptors |
| run | boolean | false | true starts the tour; false stops it |
| showProgress | boolean | true | Shows "1 / 5" counter in the footer |
| showSkipButton | boolean | true | Shows a Skip button on non-final steps |
| disableOverlayClose | boolean | false | Prevents closing when the overlay is clicked |
| spotlightPadding | number | 4 | Extra space (px) around the highlighted element |
| hideBackButton | boolean | false | Hides the Back navigation button |
| scrollToFirstStep | boolean | true | Scrolls the first target into view automatically |
| styles | WalkthroughStyles | {} | Style overrides — see Styles |
| locale | WalkthroughLocale | {} | Button label overrides — see Locale |
| callback | (data: WalkthroughCallbackData) => void | () => {} | Fired on every user action |
Step Object
interface WalkthroughStep {
target: string; // CSS selector for the element to spotlight
content: ReactNode; // String or JSX displayed in the tooltip
placement?: 'top' // Tooltip placement relative to target
| 'bottom' // (default)
| 'left'
| 'right'
| 'center'; // Centered on screen; no spotlight
}Styles
Override the visual appearance of every part of the component:
interface WalkthroughStyles {
options?: {
primaryColor?: string; // Button accent color. Default: '#e91e63'
textColor?: string; // Tooltip text color. Default: '#333'
backgroundColor?: string; // Tooltip background. Default: '#fff'
overlayColor?: string; // Backdrop color. Default: 'rgba(0,0,0,0.5)'
zIndex?: number; // Overlay z-index. Default: 10000
};
tooltip?: CSSProperties; // Extra styles for the tooltip card
buttonNext?: CSSProperties; // Extra styles for the Next / Finish button
buttonBack?: CSSProperties; // Extra styles for the Back button
buttonSkip?: CSSProperties; // Extra styles for the Skip button
}Example — brand colours:
<Walkthrough
steps={steps}
run={run}
styles={{
options: {
primaryColor: '#0078d4',
overlayColor: 'rgba(0, 0, 0, 0.6)',
zIndex: 99999,
},
buttonNext: { borderRadius: '20px' },
}}
callback={({ status }) => status !== 'running' && setRun(false)}
/>Locale
Override any button label:
interface WalkthroughLocale {
back?: string; // Default: 'Back'
next?: string; // Default: 'Next'
last?: string; // Default: 'Finish' (shown on the final step)
skip?: string; // Default: 'Skip'
}Example:
<Walkthrough
steps={steps}
run={run}
locale={{ next: 'Continue', last: 'Done', skip: 'Not now' }}
callback={({ status }) => status !== 'running' && setRun(false)}
/>Callback
The callback prop is called on every user interaction:
interface WalkthroughCallbackData {
status: 'running' | 'finished' | 'skipped';
action: 'next' | 'back' | 'skip' | 'close';
index: number; // Zero-based index of the current step
step: WalkthroughStep; // Reference to the current step object
}| status | When triggered |
|---|---|
| 'running' | The user navigated to a new step |
| 'finished' | The user completed the last step |
| 'skipped' | The user clicked Skip or the overlay |
| action | When triggered |
|---|---|
| 'next' | Next / Finish button clicked |
| 'back' | Back button clicked |
| 'skip' | Skip button clicked |
| 'close' | Overlay clicked (when disableOverlayClose is false) |
Persisting Tour State
Store progress in localStorage to avoid re-running the tour on every visit:
const [run, setRun] = useState(
localStorage.getItem('tourCompleted') !== 'true'
);
<Walkthrough
steps={steps}
run={run}
callback={({ status }) => {
if (status === 'finished' || status === 'skipped') {
setRun(false);
localStorage.setItem('tourCompleted', 'true');
}
}}
/>Browser Support
| Chrome | Firefox | Safari | Edge | |--------|---------|--------|------| | ✅ 80+ | ✅ 75+ | ✅ 13+ | ✅ 80+ |
Changelog
v2.1.0 — 2026-04-20
- Added full TypeScript declarations (
.d.ts) - Added
exportsfield (ESM + CJS + types) topackage.json - Added
enginesconstraint (node >= 14) - Removed deprecated
hideCloseButtonprop (close button removed in v2.0.4) - Professional
package.jsonwith repository, bugs, homepage fields - MIT
LICENSEfile included in published package
v2.0.4 — 2026-04-19
- Close (×) button completely removed from the tooltip
v2.0.3 — 2026-04-19
- Content text made bold;
padding-rightreduced
v2.0.2 — 2026-04-19
- Fixed close button z-index clipping and text overflow
v2.0.1 — 2026-04-19
- Initial stable release
Contributing
Issues and pull requests are welcome at
github.com/maqsoftware/react-walkthrough-screens
License
Installation
npm install react-walkthrough-screensQuick Start
import { useState } from 'react';
import Walkthrough from 'react-walkthrough-screens';
const steps = [
{
target: '.my-element',
content: 'This is the first step!',
placement: 'bottom',
},
{
target: '.another-element',
content: 'And this is the second step!',
placement: 'right',
},
];
function App() {
const [run, setRun] = useState(false);
return (
<div>
<button onClick={() => setRun(true)}>Start Tour</button>
<Walkthrough
steps={steps}
run={run}
callback={(data) => {
if (data.status === 'finished' || data.status === 'skipped') {
setRun(false);
}
}}
/>
</div>
);
}CSS is injected automatically — no separate stylesheet import needed.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| steps | Array | [] | Array of step objects (see below) |
| run | boolean | false | Start / stop the walkthrough |
| showProgress | boolean | true | Show step counter ("1 / 5") |
| showSkipButton | boolean | true | Show skip button |
| disableOverlayClose | boolean | false | Prevent closing on overlay click |
| spotlightPadding | number | 4 | Padding around the spotlight (px) |
| hideBackButton | boolean | false | Hide the back button |
| hideCloseButton | boolean | false | Hide the close (×) button |
| scrollToFirstStep | boolean | true | Scroll first step into view |
| styles | object | {} | Style overrides (see below) |
| locale | object | {} | Button label overrides |
| callback | function | () => {} | Called on every action |
Step Object
{
target: '.css-selector', // CSS selector for the element to highlight
content: 'Step text', // String or JSX
placement: 'bottom', // 'top' | 'bottom' | 'left' | 'right' | 'center'
}Styles
{
options: {
primaryColor: '#e91e63',
textColor: '#333',
backgroundColor: '#fff',
overlayColor: 'rgba(0, 0, 0, 0.5)',
zIndex: 10000,
},
tooltip: {}, // extra styles for the tooltip container
buttonNext: {}, // extra styles for the Next / Finish button
buttonBack: {}, // extra styles for the Back button
buttonSkip: {}, // extra styles for the Skip button
}Locale
{ back: 'Back', close: 'Close', last: 'Finish', next: 'Next', skip: 'Skip' }Callback
callback({ status, action, index, step })| status | When |
|----------|------|
| 'running' | Navigating between steps |
| 'finished' | Last step completed |
| 'skipped' | Skip or close clicked |
| action | When |
|----------|------|
| 'next' | Next / Finish clicked |
| 'back' | Back clicked |
| 'skip' | Skip clicked |
| 'close' | Close (×) or overlay clicked |
Author
Shoaib Hussain
License
MIT
