Skip to content

Tutorial

The Tutorial component provides a declarative way to build guided walkthroughs directly inside your UI. Each Tutorial.Step wraps real elements, highlights them, and displays a tooltip with title and content, creating a structured onboarding or feature tour.

To use the Tutorial component, wrap your existing UI with it and wrap every element you wish to be part of the tutorial with the Tutorial.Step component and provide it with an order prop.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
return (
<>
<button onclick={() => ref!.tour()}>Start tutorial?</button>
<Tutorial ref={ref} outset={5} >
<Tutorial.Step order={1} title="Welcome" content="This is the main menu.">
<button>Play</button>
</Tutorial.Step>
<Tutorial.Step order={2} title="Settings" content="Change your preferences here." position="bottom">
<button>Settings</button>
</Tutorial.Step>
</Tutorial>
</>
);
};
export default App;
Prop NameTypeDefaultDescription
styleJSX.CSSProperties{}Inline styles to apply directly to the radial menu’s root element.
classstring""Additional CSS classes to apply to the radial menu’s root element.
refTutorialRef | undefinedundefinedA reference to the component, providing access to its methods and the underlying HTML element.
outsetnumber0Extra offset (in px) applied between the tooltip/highlight and the target element. Useful when the target has shadows/borders or sits inside tight layouts.
tooltipTooltipType<T>undefinedCustom tooltip component to render instead of the default one. Receives the provided tutorial props (title, content, step, controls).
onChange(step: number) => voidundefinedFired whenever the active tutorial step changes. The callback receives the 1-based step index.

To interact with the Tutorial programmatically, you can use the TutorialRef interface. This interface provides access to the component’s root element and exposes methods for controlling its state and selection.

PropertyTypeDescription
elementHTMLDivElementRoot element of the tutorial wrapper.
progressAccessor<number>Current progress in % (0-100). Use it to display custom progress UIs.
currentAccessor<number>Current active step (1-based). Returns 0 when the tutorial is not running.
targetAccessor<HTMLElement | null>The DOM element currently being highlighted. Useful if you need any specific information about the position or dimensions of the element
MethodParametersReturn valueDescription
tour(step?: number)voidStarts the tutorial. If a step is provided, starts from that step instead of the first one.
exitvoidStops the tutorial and clears the active step.
nextvoidMoves to the next step, if any.
previousvoidMoves to the previous step, if any.
pausevoidPauses the tutorial.
resume(next?: boolean)voidResumes a paused tutorial. If next is true, it will advance to the next step on resume (useful for interactive steps).
changeStep(step: number)voidJumps directly to the provided step (1-based). Use this when the tutorial should react to external UI events.

The Tutorial component exposes:

Wraps the element you want to highlight and registers it in the tutorial flow.

Simply wrap the target element with Tutorial.Step and provide the required order prop. Providing title and content will display them in the tooltip for this step.

<Tutorial>
<Tutorial.Step order={1} title="Tabs" content="Use these to switch sections.">
<Tabs />
</Tutorial.Step>
<Tutorial.Step order={2} title="Side Panel" content="Use it for additional information." position="right" outset={-5}>
<SidePanel />
</Tutorial.Step>
</Tutorial>
Prop NameTypeDefaultDescription
ordernumberRequired. Controls the order in which the step is shown.
titlestring | undefined""Tooltip title. If omitted, an empty string is used for the step.
contentstring | undefined""Tooltip content. If omitted, an empty string is used for the step.
outsetnumber0Per-step offset. Overrides the Tutorial’s outset for this step only.
positiontop | left | right | bottomautoTooltip placement relative to the target.

You can replace the default tooltip by passing a tooltip prop to Tutorial. This prop accepts a custom component or a function that returns JSX, allowing you to fully control the tooltip’s layout, animations, and controls.

Prop NameTypeDescription
titlestring | undefinedThe current step’s title. Falls back to '' if omitted.
contentstring | JSX.Element | undefinedThe tooltip’s main content. Falls back to '' if omitted.
stepAccessor<number>The current 1-based step index.
progressAccessor<number>Current tutorial progress (0-100). Useful for showing a progress bar.
NextComponent<ComponentProps>Prebuilt “Next” button component. When clicked on the final step, it ends the tutorial.
PrevComponent<ComponentProps>Prebuilt “Previous” button component. Navigates back one step.

To declare a custom tooltip, you need to follow these steps:

  1. Create a component typed as TooltipType (you need to import the type)
  2. Pass it to the tooltip prop of the Tutorial component
  3. Use the provided props (title, content, step, progress, Next, Prev) to build your layout and behavior.
import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
import { TooltipType } from "@components/Complex/Tutorial/TutorialTooltip";
import Progress from "@components/Feedback/Progress/Progress";
import Flex from "@components/Layout/Flex/Flex";
const MyTooltip: TooltipType = (props) => {
return (
<div>
<div>{props.title}</div>
<div>{props.content}</div>
<Progress.Bar progress={props.progress()} />
<Flex>
<props.Prev>Previous</props.Prev>
<props.Next>Next</props.Next>
</Flex>
</div>
)
}
const App = () => {
let ref!: TutorialRef;
return (
<Tutorial tooltip={MyTooltip}>
<Tutorial.Step order={1} title="Tabs" content="Switch between sections here.">
<Tabs />
</Tutorial.Step>
</Tutorial>
);
};
export default App;

Optionally, you can extend the TooltipType to pass additional custom props to your tooltip component.

interface CustomTooltipProps {
customLabel: string;
}
const MyTooltip: TooltipType<CustomTooltipProps> = (props) => {
return (
<div>
<div>{props.title}</div>
<div>{props.content}</div>
<Progress.Bar progress={props.progress()} />
<Flex>
<props.Prev>Previous</props.Prev>
<props.Next>Next</props.Next>
</Flex>
<div>{props.customLabel}</div>
</div>
)
}
const App = () => {
return (
<Tutorial tooltip={(props) => <MyTooltip {...props} customLabel="Custom label" />}>
{/* ... */}
</Tutorial>
);
};
export default App;

You can start, pause, stop, and navigate the tutorial using the TutorialRef methods.

The tutorial can be started programmatically using the tour() method from the TutorialRef.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
return (
<>
<button onclick={() => ref!.tour()}>Start tutorial?</button>
<Tutorial ref={ref} >
{/* Steps go here */}
</Tutorial>
</>
);
};

You can pause the tutorial at any time using the pause() method, and resume it later with the resume() method. This behavior is useful for interactive steps where user input is required.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
const handleUserInteraction = () => {
if (ref.current() === 0) return; // Tutorial not running
if (ref.current() === 3) {
// pause on step 3
ref.pause();
// Do something...
setTimeout(() => {
// Resume after 2 seconds
ref.resume();
}, 2000);
}
};
return (
<>
<div onclick={handleUserInteraction}>
<Tutorial ref={ref} >
{/* Steps go here */}
</Tutorial>
</div>
</>
);
};

You can end the tutorial manually at any time using the exit() method from the TutorialRef.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
const handleUserInteraction = () => {
if (ref.current() === 0) return; // Tutorial not running
if (ref.current() === 3 && someCondition) {
ref.end();
}
};
return (
<>
<div onclick={handleUserInteraction}>
<Tutorial ref={ref} >
{/* Steps go here */}
</Tutorial>
</div>
</>
);
};

You can use the onChange prop to react to step changes in the tutorial. This is useful if additional logic is needed between certain steps.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
const handleStepChange = (step: number) => {
if (step === 2) {
console.log("User reached step 2, showing modal...");
// Show a modal or perform other actions
}
if (step === 4) {
ref.pause();
console.log("Tutorial paused at step 4 for user interaction.");
}
};
return (
<>
<Tutorial onChange={handleStepChange} ref={ref} >
{/* Steps go here */}
</Tutorial>
</>
);
};

You can customize individual steps of the tutorial by using the outset and position props on the Tutorial.Step component. This allows for fine-tuning the tooltip’s placement and offset for specific steps.

import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
const App = () => {
let ref!: TutorialRef;
return (
<>
<Tutorial ref={ref} outset={5} >
<Tutorial.Step order={1} outset={10} position='top' title="Welcome" content="This is the main menu." >
<button>Play</button>
</Tutorial.Step>
<Tutorial.Step order={2} outset={-5} position='right' title="Settings" content="Change your preferences here." >
<button>Settings</button>
</Tutorial.Step>
</Tutorial>
</>
);
};
export default App;

Customizing your tooltip’s behavior (Examples)

Section titled “Customizing your tooltip’s behavior (Examples)”

You can replace the default tooltip by passing a tooltip prop to Tutorial. The component you provide will receive several props to help you build your custom layout and behavior.

Manually placing the tooltip for specific steps

Section titled “Manually placing the tooltip for specific steps”

Sometimes, you may want to adjust the tooltip’s position for a particular step. You can do this by checking the current step and applying classes or inline styles that offset the tooltip as needed.

4 collapsed lines
import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
import { TooltipType } from "@components/Complex/Tutorial/TutorialTooltip";
import Flex from "@components/Layout/Flex/Flex";
const MyTooltip: TooltipType = (props) => {
return (
<div style={props.step() === 2 ? {position: 'relative', top: '10%'} : {}}>
<div>{props.title}</div>
<div>{props.content}</div>
<Flex>
<props.Prev>Previous</props.Prev>
<props.Next>Next</props.Next>
</Flex>
</div>
12 collapsed lines
)
}
const App = () => {
return (
<Tutorial tooltip={MyTooltip}>
{ /* Steps go here */ }
</Tutorial>
);
};
export default App;

Changing the next button’s content for the last step

Section titled “Changing the next button’s content for the last step”

You can customize your tooltip with the custom provided props to change the “Next” button’s content on the final step.

4 collapsed lines
import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
import { TooltipType } from "@components/Complex/Tutorial/TutorialTooltip";
import Flex from "@components/Layout/Flex/Flex";
const MyTooltip: TooltipType = (props) => {
return (
<div>
<div>{props.title}</div>
<div>{props.content}</div>
<Flex>
<props.Prev>Previous</props.Prev>
<props.Next>
{props.progress() === 100 ? 'Done' : 'Next' }
</props.Next>
</Flex>
</div>
)
}
10 collapsed lines
const App = () => {
return (
<Tutorial tooltip={MyTooltip}>
{ /* Steps go here */ }
</Tutorial>
);
};
export default App;

Applying conditional classes to control button visibility

Section titled “Applying conditional classes to control button visibility”

You can conditionally apply classes and styles to the provided Next and Prev components to control their visibility based on the current step.

4 collapsed lines
import Tutorial, {TutorialRef} from "@components/Complex/Tutorial/Tutorial";
import { TooltipType } from "@components/Complex/Tutorial/TutorialTooltip";
import Flex from "@components/Layout/Flex/Flex";
const MyTooltip: TooltipType = (props) => {
return (
<div>
<div>{props.title}</div>
<div>{props.content}</div>
<Flex>
<props.Prev class={props.step() === 1 ? 'control-hidden' : ''}>Previous</props.Prev>
<props.Next class={props.step() === 3 ? 'control-hidden' : ''}>Next</props.Next>
</Flex>
</div>
)
}
10 collapsed lines
const App = () => {
return (
<Tutorial tooltip={MyTooltip}>
{ /* Steps go here */ }
</Tutorial>
);
};
export default App;