Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactour - how to disable next step until correct user action?

I'm using the Reactour library in order to build a user tour in React (duh), which is easy enough for simple steps, but I can't figure out how to prevent the user from going further in the tour until they complete the action associated with the current step.

For example, in step 1, I want them to perform a search (enter text and submit) before continuing. Right now I'm using the goTo() function to automatically advance to the next step, but how do I prevent them from just using the navigation arrows without disabling navigation completely (in case they need to go back)?

export const steps: ReactourStep[] = [
  // This will automatically advance to the next step after a search... but the user could also just use the tour navigation instead...
  {
    selector: '.search-input',
    content: ({ goTo }: { goTo: (step: number) => void }) => {
      const searchBar = document.getElementById('search-bar') as HTMLInputElement;
      const searchButton = document.querySelector('.search-button') as HTMLButtonElement;

      // Timeout in order to allow for results to render
      searchButton.addEventListener('click', () => setTimeout(() => {
        if (searchBar.value !== '' && document.querySelector('.no-results') === null) {
          goTo(1);
        }
      }, 1000));

      return (
        <div>
          You can search using keywords and boolean expressions.
        </div>
      );
    }
  },
  {
     // Step 2 here
  }
]

I've tried using a conditional disabled boolean with a custom button too, but unlike React it doesn't re-render immediately -- only when the user revisits that step -- which defeats the whole purpose.

If it helps at all, the library GitHub has issues similar to mine but with no responses (here and here).

like image 284
yev Avatar asked Oct 11 '25 22:10

yev


1 Answers

I solved this by using a method to build the steps for the <Tour/> component, and passing in a state setter which then controls whether or not the navigation is shown/keyboard interaction is enabled:

function createSteps (setLockTour) {
  return [
    // Step which requires a specific action...
    {
      content: () => {
        return ( /* Your content */ )
      },
      action: node => {
        setLockTour(true)

        // Or whatever event you're waiting for
        node.onclick = () => {
          setLockTour(false)
          // ...
        }
      }
    }
  ]
}

Then for your tour component:

const [lockTour, setLockTour] = useState(false)
//...
<Tour
  steps={createSteps(setLockTour)}
  disableKeyboardNavigation={lockTour}
  disableDotsNavigation={lockTour}
  showButtons={!lockTour}
/>
like image 74
Tom Walters Avatar answered Oct 14 '25 12:10

Tom Walters