react-joyride
react-joyride copied to clipboard
Joyride creates duplicated DOM elements when re-running the tour
🐛 Bug Report
Package Version: 2.3.2
Hi, first of all, thanks for the great package. Please see the bug described below and Code Sandbox example with reproduction.
When implementing Joyride in controlled mode, the DOM is being duplicated on recurring runs, instead of being cleared properly.
To Reproduce
Steps to reproduce the behavior:
- Go to Code Sandbox link below
- Click on Start Tour button
- Go through all the steps
- Click on Start Tour button again
- Check HTML DOM in DevTools
Expected behavior
The DOM should be cleared whenever the tour ends or being skipped.

Link to repl or repo (highly encouraged)
Here's the integration code, just in case:
import Joyride, { STATUS } from "react-joyride";
import { useState } from "react";
const JOYRIDE_STEPS = [
{
target: "#my-first-step",
content: "This is my awesome feature!"
},
{
target: "#my-second-step",
content: "This is another awesome feature!"
},
{
target: "#my-third-step",
content: "Now this feature is the best!"
}
];
export default function App() {
const [showTour, setShowTour] = useState(true);
const handleCallback = ({ status }) => {
if ([STATUS.SKIPPED, STATUS.FINISHED].includes(status)) {
console.log("Tour finished or skipped");
setShowTour(false);
}
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => setShowTour(true)}>SHOW TOUR</button>
<h3 id="my-first-step">First Step</h3>
<h4 id="my-second-step">Second Step</h4>
<h5 id="my-third-step">Third Step</h5>
<Joyride
run={showTour}
steps={JOYRIDE_STEPS}
callback={handleCallback}
continuous
/>
</div>
);
}
having the same problem. any solution for this?
For anyone wondering, this is the solution to manually remove all the extra elements after tour finishes:
import { STATUS } from 'react-joyride'
const joyrideCallback = ({ status, index }: any) => {
if ([STATUS.FINISHED, STATUS.SKIPPED].includes(status)) {
document
.querySelectorAll('[id^="react-joyride"]')
.forEach((el) => el.remove())
}
})
<Joyride
...
callback={joyrideCallback}
...
/>
Fixed in 2.5.0