Joyful onboarding with React Joyride

Have you ever had some new functionality that you would like to showcase for your users? Perhaps your userbase is not the most tech-savvy and they need some guiding when new features are shipped. React Joyride let's you easily create guided tours that your users will enjoy.

3 min read


By Sindre Moldeklev


December 7, 2021


Let's face it, your users are probably not as tech-savvy as you are. When we develop new functionality for our intended users, it can be easy to take the functionality for granted and just assume that everyone knows how the new features work. With React Joyride we can easily create guided tours for our users, and let them know about new features and how they are to be used.

Getting started

To get started, we need to install React Joyride as an dependency

npm i react-joyride

We then have to setup our steps for the ride, and hook the steps up to our components. I like to create a new file for our steps called steps.js

// joyride/steps.js

export const steps = [
    target: "[data-joyride=favourites]",
    content: "Here you will get a glimpse of your favourites"
    target: ".add-favourite-btn",
    content: (
        <h1>You can add a new favourite with this button</h1>
        <p>Adding a new favourite helps you not forget your favourites</p>

When the steps has been created, we import the steps and add it to the Joyride component in our app

import Joyride from "react-joyride";
import { steps } from "./joyride/steps"; // Import steps

export default function App() {
  return (
    <div className="App">
      <Joyride steps={steps} run continuous /> // Add to Joyride component
      <h1>Christmas music</h1>
      <h2>Your favourites</h2>
      <ul data-joyride="favourites" className="favourites-container">
        {favourites.map((fav) => {
          return (
            <li key={fav.name}>
              <div className="favourite">
      <button data-joyride="addFavourite" className="add-favourite-btn">Add another favourite</button>

And that is it!

Here is a working example in Codesandbox

Storing when a user has seen the tour

Having a guided tour is nice, but seeing the same tour every time we load a page will annoy your users. As a bonus I will show you how you can use local storage to keep track of which steps your users has seen in your application.

First we will create a function to read from local storage

const JOYRIDE_LOCALSTORAGE_KEY = "joyride-guiding";

function getLocalstorage(): JoyrideTours {
  const stored = window.localStorage.getItem(JOYRIDE_LOCALSTORAGE_KEY);
  if (!stored) {
    return initialState;
  try {
    return JSON.parse(stored) as JoyrideTours;
  } catch (error) {
    return initialState;

This function will let us fetch the item stored under the joyride-guiding key. As I am using Typescript, I tell the code that when I return JSON.parse, the type returned will be of type JoyrideTours.

We will also need a function to store some state in local storage

function saveToLocalstorage(tours: JoyrideTours) {
  window.localStorage.setItem(JOYRIDE_LOCALSTORAGE_KEY, JSON.stringify(tours));

Here I just stringify the object tours and save them to the key JOYRIDE_LOCALSTORAGE_KEY in local storage.

Finally, we need to be able to listen for the callback event from the tour. We will do that with a new function, connected to the callback-property from the Joyride component

function handleJoyrideCallback(callback: CallBackProps, page: Pages) {
  const { status, action } = callback;
  if (status === STATUS.FINISHED || action === ACTIONS.CLOSE) {
    const tours = getLocalstorage();
    const saveTours = { ...tours, [page]: true };

// Component below is what we will render with React
  callback={(e: CallBackProps) => { // Here we can call our own function with whatever data we want
    handleJoyrideCallback(e, "my-page");

In this last block of code, we define a function handleJoyrideCallback which takes a callback from Joyride, as well as our own defined page variable. We then check wether the status is equal to STATUS.FINISHED or ACTIONS.CLOSE, and if they are, we store in local storage that the user has seen the page we provided.

The final piece of the puzzle is to not run the tour if the user has already seen it. Otherwise they will get annoyed. To accomplish this, we do as follows

const tours = getLocalstorage();

  run={!tours.page} // If the user has not seen tours.page, we run, otherwise don't run
  callback={(e: CallBackProps) => {
    handleJoyrideCallback(e, "tilbakemelding");

We get the tours from our local storage, and simply check if the page the user is requesting has not been seen. If not we run the joyride tour, otherwise we do not run it.

And there you have it, a rather simple implementation of how to make guided tours in your application. Quick and easy.