Build interactive product tours with spotlights, tooltips, and step-by-step guidance — without being tied to a framework.
I've just released Stepr v0.1.0, an open-source TypeScript library for building guided product tours.
Why I built Stepr
Guided product tours can be a great way to introduce users to an application.
Whether you're onboarding someone for the first time, introducing a new feature, or explaining a complicated interface, sometimes it's easier to show people where to click than to write another page of documentation.
There are already several libraries that solve this problem.
But I wanted to explore building something smaller and more focused.
My goals were straightforward:
- Framework-agnostic: Work with plain JavaScript, React, Vue, or other frontend frameworks.
- Lightweight: No runtime dependencies.
- Simple API: Make it easy to highlight an element or start a guided tour.
- Accessible: Consider keyboard navigation, focus management, and screen readers from the beginning.
- TypeScript-first: Provide a typed API without requiring TypeScript in consuming projects.
That became Stepr.
What is Stepr?
Stepr provides three main building blocks for guided user experiences.
1. Spotlight
Highlight an element while dimming the rest of the page.
This is useful when you want to draw attention to a particular button, form field, or feature.
The spotlight follows the target element as the page changes position through scrolling or resizing.
2. Tooltip
Display contextual information next to an element.
Tooltips can contain a title and description, and Stepr handles placement adjustments to keep them within the viewport.
3. Guided tours
Combine spotlights and tooltips into a sequence of steps.
Each step points to an element and explains what the user should know about it.
Stepr manages navigation between steps, keyboard interactions, and the lifecycle of the tour.
Getting started
Install Stepr from npm:
npm install stepr Stepr is distributed as an ES module and includes TypeScript declarations.
Create your first tour
Suppose your application has a few elements you want to introduce:
<button id="create-project">Create project</button> <nav id="main-navigation"> <!-- Your navigation --> </nav> <section id="dashboard"> <!-- Your dashboard --> </section> You can create a tour by defining the steps:
import { createTour } from 'stepr'; const tour = createTour({ steps: [ { target: '#create-project', title: 'Create your first project', description: 'Start here to create a new project.', }, { target: '#main-navigation', title: 'Find your way around', description: 'Use the navigation to explore the app.', }, { target: '#dashboard', title: 'Your dashboard', description: 'See an overview of your projects here.', }, ], }); document .querySelector('#start-tour') ?.addEventListener('click', () => tour.start()); That's the basic idea.
Define the elements you want to introduce, provide the content for each step, and start the tour.
Stepr handles the spotlight, tooltip, and step navigation.
Accessibility matters
Accessibility was an important part of the project from the beginning.
Product tours can introduce accessibility challenges, particularly when overlays and floating elements are involved.
Stepr includes support for:
- Keyboard navigation and Escape to exit.
- Focus management and focus restoration.
- Screen reader announcements.
- Accessible tooltip labels and descriptions.
- Reduced-motion preferences.
The tooltip uses a non-modal dialog pattern, allowing users to continue interacting with the surrounding page.
This is an important design decision: a product tour shouldn't automatically trap users in an interface they can't escape.
Accessibility still depends on how a tour is integrated into the application, so testing with actual assistive technology remains important.
Framework-agnostic by design
One of my main goals was to avoid coupling Stepr to a particular frontend framework.
The library works directly with DOM elements and selectors.
That means it can be used in a plain HTML application or integrated into a framework-based project.
For example, a React application can create a tour after the relevant elements have mounted, while a vanilla JavaScript application can start one directly from an event handler.
The underlying library stays the same.
No runtime dependencies
Stepr has no runtime dependencies.
For a library focused on a relatively small set of UI behaviors, I wanted to keep the installation and integration straightforward.
This doesn't automatically make it the best solution for every project, but it does make it easier to evaluate and adopt without bringing in additional packages.
Try the interactive demo
I've also built a small interactive demo where you can see Stepr in action.
The demo walks through a fictional invoicing application, highlighting interface elements and explaining how they work.
You can try it here:
👉 https://ahlgren1234.github.io/stepr/
The demo also includes an installation command that you can copy directly.
What's next?
Version 0.1.0 is the first public release.
For now, my priority is to see how the library works in real projects and learn from developer feedback.
I'm particularly interested in hearing about:
- API usability and integration experiences.
- Accessibility issues or improvements.
- Edge cases involving scrolling, positioning, or dynamic interfaces.
- Features that would genuinely make product tours easier to build.
I'd rather keep the library focused than add features simply for the sake of adding them.
Final thoughts
Stepr started as an experiment in building a small, reusable TypeScript library with a clear purpose.
It's now available as an open-source package, and I'm looking forward to seeing whether other developers find it useful.
If you're building an onboarding experience, a feature walkthrough, or a guided interface, give it a try.
Links:
- Live demo: https://ahlgren1234.github.io/stepr/
- GitHub: https://github.com/ahlgren1234/stepr
- npm: https://www.npmjs.com/package/stepr
Feedback, issues, and contributions are welcome!
Tags: #typescript #javascript #opensource #webdev

