Next.js Onboarding with Reactour (Tour.js)

Tour.js is a free JavaScript library for user onboarding. This library guides users through complex features of your application. By making an app easier to navigate, you can increase traffic and decrease the bounce rate upon first interaction. This post will go over a simple example of how to run Tour.js on a single page with a MUI components. This demo uses MUI Version 5.x.

Source Files

GitHub

Prerequisites

If you are not using the source files above then get the Next.js template from MUI. You might have to clone the entire repository to get it, but it is worth the effort. The template from MUI has everything configured out of the box and is ready to use. Installing Material manually can be challenging if you are still a novice with Next.js.

https://github.com/mui/material-ui/tree/master/examples/nextjs

React Tour – Onboarding Library

Install Reactour which is a wrapper for Tour.js.

https://www.npmjs.com/package/reactour

npm i reactour

Install Styled-Components for Tour.js.

npm i styled-components

MUI Table Component – (Optional)

Create a component labeled BasicTable under ‘./components’. Copy the code from MUI (below). This is for the demo page.

https://mui.com/material-ui/react-table/#basic-table

CSS Styling for the Tour

Create a style sheet under ‘./styles’ labeled tour.module.css

.mask {    
  opacity: 0.6;
  color: #A0A0A0;
  color: white;
  
}

.helper {
  --reactour-accent: #5cb7b7;
  line-height: 1.3;
  color: #2d2323;
  opacity: 0.8;
}

The Demo Page

Create the Tour page under ‘./pages labeled as ‘./pages/tour.js’.

Below are all of the imports for the demo.

import React from "react";
import Button from "@mui/material/Button";
import Slide from "@mui/material/Slide";
import dynamic from 'next/dynamic';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import style from '../../styles/tour.module.css'
import TextField from '@mui/material/TextField';
import BasicTable from "../../components/BasicTable";  // The table component created earlier

Import reactour Dynamically

Import reactour dynamically since it cannot be rendered on the server.

import dynamic from 'next/dynamic';
...
const Tour = dynamic(
  () => import('reactour'),
  { ssr: false },
);

Single Step Example

Example of a single reactour step. You have the selector and the content you want to display for that step.

const tourConfig = [
  {
    selector: '[data-tut="reactour__iso"]',
    content: `Ok, let's start with the name of the Tour that is about to begin.`,    
  },  
];

Styling to a Step

Import reactour dynamically since it cannot be rendered on the server.

const tourConfig = [
  {
    selector: '[data-tut="reactour__iso"]',
    content: `Ok, let's start with the name of the Tour that is about to begin.`,    
    style: {
        color: "black"      
    }
  },  
];

Event Handing for Reactour

Import reactour dynamically since it cannot be rendered on the server.

  const accentColor = "#5cb7b7";

  const [isTourOpen, setTourOpen] = React.useState(false);

  const handleClickOpen = () => {
    setOpen(true);
  };

  const closeTour = () => {
    setTourOpen(false);
  };
  
  const openTour = () => {
    handleClickOpen(true);
    setTourOpen(true);
  };

Configuring Reactour

Put the <Tour/> component somewhere in the rendering part of the page.

The following properties are used in this example

  <Tour
    onRequestClose={closeTour}
    disableInteraction={false}
    steps={tourConfig}
    isOpen={isTourOpen}
    maskClassName={style.mask}
    className={style.helper}
    rounded={5}
    accentColor={accentColor}
    disableInteraction={true}
    
  />

accentColor={accentColor}

nRequestClose={closeTour}

All together

All of the source code for the demo page.

import React from 'react';
import Button from '@mui/material/Button';
import Slide from '@mui/material/Slide';
import dynamic from 'next/dynamic';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import style from '../styles/tour.module.css'
import TextField from '@mui/material/TextField';
import Grid from '@mui/material/Grid';
import Container from '@mui/material/Container';
import BasicTable from '../components/BasicTable';
import Head from 'next/head';

const Tour = dynamic(
  () => import('reactour'),
  { ssr: false },
);
  
const Transition = React.forwardRef(function Transition(props, ref) {
  return <Slide direction="up" ref={ref} {...props} />;
});

const tourConfig = [
  {    
    selector: '[data-tut="reactour__iso"]',
    content: `This is a button`,    
  },
  {    
    selector: '[data-tut="reactour__finalbutton"]',
    content: `This is a text field...`,    
  },
  {
    selector: '[data-tut="reactour__box"]',
    content: ({ goTo }) => (
      <div>
        Table description
        <br /> 
        You can go back to the 1st step
        <br /> 
        <br /> 
        <Button color="primary" variant="outlined"
          onClick={() => goTo(0)}
          style={{
            display: "block",
            margin: "1em auto"
          }}
        >
          Go back to step 1
        </Button>
      </div>
    )
  },
  
];
export default function Index() {
  const accentColor = "#5cb7b7";

  const [isTourOpen, setTourOpen] = React.useState(false);

  const closeTour = () => {
    setTourOpen(false);
  };

  const openTour = () => {
    
    setTourOpen(true);
  };


  return (
    
    <div>
      <Head>
        <link rel="shortcut icon" href="/favicon.ico" />
        <title>Full Stack Soup - Reactour Demo</title>
      </Head>

      <Stack spacing={2} 
      mt={4}
      justifyContent="flex-start"
      alignItems="center">
      
      
      <Tour
        onRequestClose={closeTour}
        disableInteraction={false}
        steps={tourConfig}
        isOpen={isTourOpen}
        maskClassName={style.mask}
        className={style.helper}
        rounded={5}
        accentColor={accentColor}
        disableInteraction={true}
        
      />

      <Container maxWidth="lg">
        <Grid container spacing={4}>
            <Grid item xs={12} align="center">
              <Button variant="outlined" color="secondary" onClick={openTour}>
                Open Tour
              </Button>        
            </Grid>
            <Grid item xs={6}>
              <Button
                  data-tut="reactour__iso"
                  autoFocus
                  
                  color="primary"
                  variant="contained"
                >
                  Save changes
              </Button>
          
            </Grid>
            <Grid item xs={6}>
              <TextField id="outlined-basic" size="small" label="Outlined" variant="outlined" data-tut="reactour__finalbutton"/>
          
            </Grid>
            <Grid item xs={12}>
              <Box
              data-tut="reactour__box"
              sx={{
                  width: '100%',
                  height: 500,
              }}>
                <BasicTable/>
              </Box>
        
            </Grid>
        </Grid>
      </Container>
                                
      </Stack>      
    </div>
  );
}

Automatically show for first time visitors.

Using the browser’s local storage to store a value when the user has visited the page or application.

if(!localStorage.getItem('somekey')) {
    localStorage.setItem('somekey', 'true')
    setTourOpen(true)
}

Conclusion

Now that you know the basics of Tour.js, try putting the steps in a separate file or decorate the steps with buttons and colors. If Tour.js isn’t for you, check out some of the other onboarding libraries below.

https://introjs.com/

https://react-joyride.com/