Product Tours with React

Ryan Delaney

Tuesday June 8th 2021

RevereCRE/react-spotlight-tour
Self-configuring product tour library for React
Go to the repo

The Problem with Product Tours

Starting off a post called Product Tours in React with a whole section dissing product tours? That's bold.

When our engineering team wanted to start implementing product tours into our web app we started looking around at common approaches used by other app and we weren't thrilled with what we saw. Many apps use the common approach of small pop-up boxes appearing one after another all over the screen. Our goal here is to help our users on their journey to being Revere power users, not rattle off a list of features that might not be immediately useful. We asked our product team for a quick show of hands: "How many of you have actually finished one of these tours?"; only to find out not a single person asked ever finished one.

We looked into this a little more and found some sad results: the average completion rate for a product tour is 61% and declines to <50% when the tour has more than two steps. It seemed like this approach was bound to be something our engineering team maintained that provided no value to our users — something an early stage startup cannot afford.

On the subject of maintaining our product well into the future, each of the libraries we researched seemed old-school for a React-based approach; even the ones that were designed for React. Rather than configuring the tour near the component being showcased there was always one mega-config object per-page that specified step-order and a bunch of selectors. This is in direct contrast to one of our core engineering principals at Revere: composability. We don't want to have to re-configure each tour when we move components around, the components themselves should specify that they should be part of the tour. A big disadvantage of this selector-based approach is that there cannot be static validation that the tour still works when a component changes.

In summary, from our research most product tour libraries have two common issues:

  1. They depend on static selectors, removing locality from configuration.
  2. They encourage lengthy tours that users won't ever get to the end of.

A Fresh Approach

When implementing product tours in Revere we set out to solve both of these issues by creating a new library: React Spotlight Tour. It addresses both of the issues above:

  1. They depend on static selectors, removing locality from configuration. We use React's refs and context to grab references to elements at runtime, rather than querying the entire DOM. This also lets users of the library dynamically configure their tour.

  2. They encourage lengthy tours that users won't ever get to the end of. We use a design inspired by Chardin.js that shows a lightweight overlay on the app with selected elements spotlighted that can be dismissed with a click. There's no mutliple steps, only the spotlight. This helps our users in that even if they don't really pay attention to the tour we can still point them in the right direction.

Some examples of how this is implemented in Revere:

Screenshot of UI using React Spotlight Tour Screenshot of UI using React Spotlight Tour Screenshot of UI using React Spotlight Tour

Reusability is key here — we want to be able to introduce tours and tutorials with very minimal overhead. While it's definitely not the most complex tour library out there it shines in its simplicity, ease of use, and composability. Some sample code from our docs:

import { useState } from 'react';
import { SpotlightTour, useSpotlight } from 'react-spotlight-tour';
import Spotlight from 'react-spotlight-tour/spotlight';

function StatusUpdateInput() {
  const spotlightRef = useSpotlight('Update your status');

  // ...

  return (
    <div ref={spotlightRef}>
      <textarea />
      <button>Update status</button>
    </div>
  );
}

function HomePage() {
  const [isOpen, setOpen] = useState(false);

  return (
    <SpotlightTour
      open={isOpen}
      onClose={() => setOpen(false)}
      Spotlight={HighlSpotlightghter}
    >
      <StatusUpdateInput />
    </SpotlightTour>
  );
}

We love how easy it is to introduce new tutorials and highlights at the component-level rather than the page-level. Our users love how lightweight it feels while still being helpful. We hope you enjoy using the library as well! Feel free to check out the GitHub repo, live demo, and documentation.

While you're here, Revere is hiring! Check out our other blog posts, open positions, and reach out to us if it sounds interesting!