useJoyride Hook

The useJoyride hook gives you direct access to the tour's controls, state, current step, failures, and event subscriptions. It replaces the getHelpers component prop from V2.

It's the recommended approach for any tour that reacts to state, coordinates with external UI, or needs explicit control. The <Joyride /> component is a convenience wrapper around it.

See it in action

The Custom Components demo shows programmatic controls and state display.

The Carousel demo uses event subscriptions to sync external UI.

Usage

import { useEffect } from 'react';
import { useJoyride } from 'react-joyride';
 
const steps = [
  { target: '[data-step="1"]', content: 'First step' },
  { target: '[data-step="X"]', content: 'Second step is missing' },
  { target: '[data-step="3"]', content: 'Third step' },
];
 
function App() {
  const { controls, failures, on, state, Tour } = useJoyride({
    continuous: true,
    steps,
  });
 
  useEffect(() => {
    return on('tour:end', () => {
      console.log('The tour has ended');
    });
  }, [on]);
 
  useEffect(() => {
    if (failures?.length) {
      console.log(failures?.at(-1));
    }
  }, [failures]);
 
  return (
    <div>
      <div data-step="1">Step 1</div>
      <div data-step="3">Step 3</div>
      <button onClick={() => controls.start()} type="button">
        Start Tour
      </button>
      <p>Status: {state.status}</p>
      {Tour}
    </div>
  );
}

The hook accepts the same props as the <Joyride /> component.

Return Value

FieldType

controls

Methods to programmatically control the tour.

Controls

failures

Steps that failed during the tour (target not found, before hook errors). Clears on start/reset.

StepFailure[]

on

Subscribe to a specific event type. Returns an unsubscribe function.

(eventType: Events, handler: EventHandler) => () => void

state

The current tour state.

State

step

The current step with all defaults applied, or null if no step is active.

StepMerged | null

Tour

The tour React element to render. Must be included in your JSX.

ReactElement | null
warning

You must render {Tour} in your component's JSX. Without it, nothing will be displayed.

Controls

Methods to programmatically control the tour. All methods are stable references (they don't change between renders).

MethodType

start

Start the tour. Optionally pass a step index to start from.

Equivalent to setting run={true}.

(nextIndex?: number) => void

stop

Stop (pause) the tour. If advance is true, the index advances before stopping.

Equivalent to setting run={false}.

(advance?: boolean) => void

next

Advance to the next step. Only works when the tour is running.

() => void

prev

Go back to the previous step. Only works when the tour is running.

() => void

go

Jump to a specific step by index. Only works in uncontrolled mode.

(nextIndex: number) => void

close

Close the current step and advance to the next one.

(origin?: Origin | null) => void

skip

Skip the tour entirely.

(origin?: 'button_close' | 'button_skip') => void

open

Open the tooltip for the current step (skip the beacon).

() => void

reset

Reset the tour to step 0. If restart is true, the tour starts again immediately. Only works in uncontrolled mode.

(restart?: boolean) => void

info

Get a snapshot of the current tour state.

() => State

Event Subscriptions

The on method lets you subscribe to specific event types without filtering in onEvent. It returns an unsubscribe function.

on is a stable reference — it doesn't change between renders, making it safe for useEffect dependencies.

import { useEffect } from 'react';
import { useJoyride } from 'react-joyride';
 
function App() {
  const { on, Tour } = useJoyride({ steps, continuous: true });
 
  useEffect(() => {
    return on('step:before', (data, controls) => {
      console.log(`Entering step ${data.index}`);
    });
  }, [on]);
 
  return <>{Tour}</>;
}
tip

The handler receives EventData and Controls as arguments — the same as onEvent. Since data contains the full tour state (index, action, status, etc.), you rarely need external state in the handler.

warning

Always return the unsubscribe function from useEffect to prevent duplicate subscriptions in StrictMode.

State

FieldDescriptionType
actionThe action that triggered the last state updateActions
controlledWhether the tour is in controlled mode (using stepIndex)boolean
indexThe current step indexnumber
lifecycleThe step's rendering phaseLifecycle
originThe UI element that triggered the last actionOrigin | null
scrollingWhether the tour is currently scrolling to a targetboolean
sizeThe total number of stepsnumber
statusThe tour's current statusStatus
waitingWhether the tour is blocked waiting for a before hook or target to appearboolean

Controlled vs Uncontrolled

The hook works in both modes. See How It Works for the full explanation and code examples.

  • Uncontrolled (default): Joyride manages the step index. Use controls to navigate programmatically.
  • Controlled (with stepIndex): You manage the index via onEvent. go() and reset() are disabled in this mode.