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.
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
| Field | Type |
|---|---|
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 | StepMerged | null |
Tour The tour React element to render. Must be included in your JSX. | ReactElement | null |
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).
| Method | Type |
|---|---|
start Start the tour. Optionally pass a step index to start from. Equivalent to setting | (nextIndex?: number) => void |
stop Stop (pause) the tour. If Equivalent to setting | (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?: 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}</>;
}Always return the unsubscribe function from useEffect to prevent duplicate subscriptions in StrictMode.
State
| Field | Description | Type |
|---|---|---|
action | The action that triggered the last state update | Actions |
controlled | Whether the tour is in controlled mode (using stepIndex) | boolean |
index | The current step index | number |
lifecycle | The step's rendering phase | Lifecycle |
origin | The UI element that triggered the last action | Origin | null |
scrolling | Whether the tour is currently scrolling to a target | boolean |
size | The total number of steps | number |
status | The tour's current status | Status |
waiting | Whether the tour is blocked waiting for a before hook or target to appear | boolean |
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
controlsto navigate programmatically. - Controlled (with
stepIndex): You manage the index viaonEvent.go()andreset()are disabled in this mode.