Lorem ipsum dolor, sit amet consectetur adipisicing elit. Maiores, atque, pariatur blanditiis distinctio quam cum minus soluta ea, possimus eaque neque perferendis fugiat accusamus assumenda voluptatibus molestias corrupti natus hic dolor a in quasi? Cupiditate totam iste illo hic ut asperiores laudantium molestias sequi nesciunt, a voluptatem, cumque repellat magni harum tempore, fuga pariatur. Totam, est nam ullam beatae praesentium sed possimus incidunt quo perspiciatis earum. Quisquam doloribus inventore, nobis eos tenetur non tempora consequuntur rerum hic at perspiciatis nemo reiciendis, alias unde cupiditate modi totam quibusdam recusandae est quidem molestiae laudantium a ipsam excepturi. Reprehenderit voluptas unde temporibus modi!
How to improve product-tour functionality for a site made with React
After figuring out different approaches to improving a product-tour on a web-site, I have decided to create a simplified version with React. Here is the final code with a few adjustments.
MainPage.jsx
import { useMemo, useState } from "react";
import Hint from "./components/Hint";
export default function MainPage() {
const steps = useMemo(
() => [
{ id: "title", text: "Title is shown here." },
{ id: "text", text: "Text is shown here." },
],
[],
);
const [isTourOpen, setIsTourOpen] = useState(false);
const [stepIndex, setStepIndex] = useState(0);
const currentStep = isTourOpen ? steps[stepIndex] : null;
const startTour = () => {
setStepIndex(0);
setIsTourOpen(true);
};
const endTour = () => {
setIsTourOpen(false);
setStepIndex(0);
};
const next = () => {
setStepIndex((i) => Math.min(i + 1, steps.length - 1));
};
const prev = () => {
setStepIndex((i) => Math.max(i - 1, 0));
};
return (
<main className="flex flex-col items-center justify-center">
<button
onClick={()=> (isTourOpen ? endTour() : startTour())}
className="border-3 z-50 min-w-28 cursor-pointer border-blue-950 bg-blue-800 p-1 text-xs font-bold uppercase text-gray-100 hover:bg-gray-100 hover:text-blue-950"
>
{isTourOpen ? "End tour" : "Start tour"}
</button>
<section className="relative">
{currentStep?.id === "title" && (
<Hint
text={currentStep.text}
onClose={endTour}
onNext={next}
onPrev={prev}
isFirst={stepIndex= 0}
isLast={stepIndex= steps.length - 1}
/>
)}
<h2 className="border-3 w-full max-w-2xl bg-blue-950 p-1 text-center text-2xl font-bold">
Title
</h2>
<article className="relative">
{currentStep?.id === "text" && (
<Hint
text={currentStep.text}
onClose={endTour}
onNext={next}
onPrev={prev}
isFirst={stepIndex= 0}
isLast={stepIndex= steps.length - 1}
/>
)}
<p className="border-3 w-full max-w-2xl bg-blue-950 p-4">
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Maiores,
atque, pariatur blanditiis distinctio quam cum minus soluta ea,
possimus eaque neque perferendis fugiat accusamus assumenda
voluptatibus molestias corrupti natus hic dolor a in quasi?
Cupiditate totam iste illo hic ut asperiores laudantium molestias
sequi nesciunt, a voluptatem, cumque repellat magni harum tempore,
fuga pariatur. Totam, est nam ullam beatae praesentium sed possimus
incidunt quo perspiciatis earum. Quisquam doloribus inventore, nobis
eos tenetur non tempora consequuntur rerum hic at perspiciatis nemo
reiciendis, alias unde cupiditate modi totam quibusdam recusandae
est quidem molestiae laudantium a ipsam excepturi. Reprehenderit
voluptas unde temporibus modi!
</p>
</article>
</section>
{/* Darkening effect for the page */}
{isTourOpen && (
<div
onClick={endTour}
className="pointer-events-auto fixed inset-0 z-40 bg-black/40"
aria-hidden="true"
/>
)}
</main>
);
}
Hint.jsx
export default function Hint({
text,
onNext,
onPrev,
onClose,
isFirst,
isLast,
}) {
return (
<aside className="hint-contentWrapper absolute -top-5 z-50 mx-2 w-full max-w-[200px] text-center">
<div className="border-3 border-blue-950 bg-gray-100 px-2 py-1 text-xs text-blue-950">
<p className="text-sm">{text}</p>
<div className="mt-2 flex items-center justify-between gap-2">
<button
onClick={onPrev}
disabled={isFirst}
className="border-2 border-blue-950 px-2 py-1 hover:bg-blue-950 hover:text-gray-200 disabled:opacity-50"
>
Prev.
</button>
{isLast ? (
<button
onClick={onClose}
className="border-2 border-blue-950 px-2 py-1"
>
Finish
</button>
) : (
<button
onClick={onNext}
className="border-2 border-blue-950 px-2 py-1 hover:bg-blue-950 hover:text-gray-200"
>
Next
</button>
)}
<button
onClick={onClose}
className="border-2 border-blue-950 px-2 py-1 hover:bg-blue-950 hover:text-gray-200"
>
Close
</button>
</div>
</div>
<div className="border-t-10 border-r-10 border-l-10 mx-auto h-0 w-0 border-l-transparent border-r-transparent border-t-blue-950" />
</aside>
);
}
Live version
Styling has been slightly modified to match the design of the current site.
Title
Thank you for reading.