Configuration
Pass options to driver(). Options marked step can also be set on a single step, where they override the driver’s value.
import { driver } from "driver.js";
import "driver.js/dist/driver.css";
const driverObj = driver({
showProgress: true,
overlayOpacity: 0.5,
steps: [
{
element: "#search",
popover: { title: "Search", description: "Find anything." },
},
{
element: "#export",
disableActiveInteraction: true,
popover: { title: "Export", side: "left" },
},
],
});
driverObj.drive();
Each driver() call is its own instance with its own configuration, steps and state. Only one instance is on screen at a time: starting one closes any other. To change options later, use setConfig().
All types on this page are exported from driver.js.
Driver Configuration
type Config = {
// The steps of the tour. Not needed for highlight().
steps?: DriveStep[];
// --- Overlay and highlight ---
// Animate between steps. (default: true)
animate?: boolean;
// Length of that animation and of the fade-in, in milliseconds.
// (default: 400)
duration?: number;
// Any CSS color. (default: "#000")
overlayColor?: string;
// (default: 0.7)
overlayOpacity?: number;
// Space between the element and the edge of the cutout, in pixels.
// (default: 10)
stagePadding?: number;
// Corner radius of the cutout, in pixels. (default: 5)
stageRadius?: number;
// Scroll smoothly to the highlighted element. (default: false)
smoothScroll?: boolean;
// Let the page scroll while the tour is open. (default: true)
allowScroll?: boolean;
// --- Closing and navigation ---
// Let the user close the tour: with the close button, Escape or a click
// on the overlay. false also hides the close button. (default: true)
allowClose?: boolean;
// What a click on the overlay does. A function replaces the default and
// receives the same arguments as a hook. (default: "close")
overlayClickBehavior?: "close" | "nextStep" | "none" | DriverHook;
// Arrow keys move between steps and Escape closes. (default: true)
allowKeyboardControl?: boolean;
// --- Interaction (all step) ---
// Block the highlighted element: true turns off all pointer events
// on it, "clicks" keeps hover and blocks clicks. (default: false)
disableActiveInteraction?: boolean | "clicks";
// Complete the step when this event happens on the highlighted element.
// (default: off)
advanceOn?: false | string | string[] | AdvanceOnEvent;
// Milliseconds to pause after advanceOn or advance() completes a step,
// before moving on. (default: 0)
advanceDelay?: number;
// Other elements the user may use during a step, like a menu it opens.
allowedElements?: AllowedElements;
// Called for every click during a step. Return false to block it.
onInteraction?: InteractionHook;
// Deprecated: use advanceOn: "click".
advanceOnClick?: boolean;
// --- Missing elements (all step) ---
// Milliseconds to wait for a step's element to appear.
// (default: 0, no wait)
waitForElement?: number;
// Skip a step whose element is not on the page. (default: false)
skipMissingElement?: boolean;
// What to do when the highlighted element leaves the page for good, or a
// wait runs out. (default: "stay")
onElementMissing?: ElementMissing;
// --- Popover defaults (see Popover Configuration) ---
popoverClass?: string;
// Space between the popover and the cutout, in pixels. (default: 10)
popoverOffset?: number;
// (default: ["next", "previous", "close"] in a tour, [] in highlight())
showButtons?: ("next" | "previous" | "close")[];
disableButtons?: ("next" | "previous" | "close")[];
showProgress?: boolean;
progressText?: string;
nextBtnText?: string;
prevBtnText?: string;
doneBtnText?: string;
closeBtnLabel?: string;
// --- Hooks (see Hooks) ---
onPopoverRender?: (popover: PopoverDOM, opts: HookOpts) => void;
onHighlightStarted?: DriverHook;
onHighlighted?: DriverHook;
onDeselected?: DriverHook;
onDestroyStarted?: DriverHook;
onDestroyed?: DriverHook;
onNextClick?: DriverHook;
onPrevClick?: DriverHook;
onCloseClick?: DriverHook;
onDoneClick?: DriverHook;
};
Step Configuration
A step is what you put in steps or pass to highlight().
type DriveStep = {
// What to highlight: a CSS selector (first match), an element, or a
// function returning one. Without it the popover is centered on the
// screen.
element?: string | Element | (() => Element);
// The popover of this step. See Popover Configuration.
popover?: Popover;
// Your own data, readable from the step in any hook.
data?: Record<string, any>;
// Per-step versions of the driver options with the same name.
disableActiveInteraction?: boolean | "clicks";
advanceOn?: false | string | string[] | AdvanceOnEvent;
advanceDelay?: number;
allowedElements?: AllowedElements;
onInteraction?: InteractionHook;
waitForElement?: number;
skipMissingElement?: boolean;
onElementMissing?: ElementMissing;
advanceOnClick?: boolean;
// Per-step hooks. They run instead of the driver's.
onHighlightStarted?: DriverHook;
onHighlighted?: DriverHook;
onDeselected?: DriverHook;
};
If a step names an element that is not on the page, its popover is centered like a step without one, unless waitForElement or skipMissingElement says otherwise.
Popover Configuration
Set on a step’s popover. The options that also exist on the driver fall back to the driver’s value.
type Popover = {
// HTML is allowed in both. Leave one out to show only the other.
title?: string;
description?: string;
// Side of the element the popover sits on. It flips when it doesn't fit.
// (default: "bottom")
side?: "top" | "right" | "bottom" | "left";
// Position along that side. (default: "start")
align?: "start" | "center" | "end";
// Buttons to show, and buttons to show but disable.
showButtons?: ("next" | "previous" | "close")[];
disableButtons?: ("next" | "previous" | "close")[];
// (defaults: "Next", "Previous", "Done")
nextBtnText?: string;
prevBtnText?: string;
// Text of the next button on the last step.
doneBtnText?: string;
// Screen reader label of the close button. (default: "Close")
closeBtnLabel?: string;
// Show the step count. (default: false)
showProgress?: boolean;
// {{current}} and {{total}} are replaced.
// (default: "{{current}} of {{total}}")
progressText?: string;
// Extra class on the popover, for styling.
popoverClass?: string;
// Makes the step an action step: the user has to do this to move on.
// HTML is allowed. See Action Steps below.
instruction?: string;
// Per-step hooks. They run instead of the driver's.
onPopoverRender?: (popover: PopoverDOM, opts: HookOpts) => void;
onNextClick?: DriverHook;
onPrevClick?: DriverHook;
onCloseClick?: DriverHook;
onDoneClick?: DriverHook;
};
Examples for position, buttons and custom buttons are in the Popover guide.
Action Steps
An action step is a step with popover.instruction. The instruction shows in its own row, ending in a pulsing dot while the step waits, and the step only completes through advanceOn, advance() or moveNext(). The Next button, when showButtons has it, stays in its place but looks disabled (aria-disabled): pressing it, the right arrow key or the overlay shakes the popover instead of moving on, and onNextClick doesn’t run. Previous, the close button and Escape work as usual. With advanceDelay, the dot becomes a check mark and the row and Next turn green for the pause; screen readers hear your doneBtnText (“Done”) once. In highlight() the instruction is a plain line and nothing is gated.
{
element: "#inbox",
advanceOn: "click",
popover: {
title: "Open your inbox",
instruction: "Click <b>Inbox</b>.",
},
}
In highlight(), action is only an instruction line. See Action-Driven Tours for live examples.
Interaction
By default the user can use the highlighted element, and nothing else on the page. These options change that.
| You want to… | Use |
|---|---|
| Move on when the user clicks, types or picks something | advanceOn: "click", "input", "change", … |
| Move on only when the result is right | advanceOn: { event, when } |
| Accept one gesture on the element and block other clicks | advanceOn: { event, strict: true } |
| Take away the Next button so the user has to act | popover.instruction |
| Let the user use something outside the element, like a menu | allowedElements |
| Let the user look but not touch | disableActiveInteraction: true |
| Keep hover and tooltips, block clicks | disableActiveInteraction: "clicks" |
| Decide per click, or react to a wrong click | onInteraction |
| Choose what a click on the dimmed page does | overlayClickBehavior |
advanceOn
type AdvanceOnEvent = {
event: string | string[];
when?: (
element: Element,
step: DriveStep,
opts: HookOpts & { event: Event }
) => boolean;
strict?: boolean;
};
eventis any DOM event name that reaches the highlighted element, or a list of them.whenruns after your app has handled the event. The step completes only when it returnstrue.strict: truemakes the element take only that gesture: other clicks, right-clicks and double-clicks on it are blocked and shake the popover. It applies when every event is a pointer gesture (click,dblclick,contextmenu,auxclick, pointer and mouse down and up).falseon a step turns off the driver’sadvanceOnfor it.
Completing a step runs onNextClick like the Next button does, or onDoneClick on the last step.
onInteraction
type InteractionHook = (
element: Element | undefined,
step: DriveStep,
opts: HookOpts & {
event: MouseEvent;
region: "element" | "allowed" | "outside";
}
) => false | void;
Called for every click, auxclick, contextmenu and dblclick during a step, before your app’s handlers. region says where it happened: on the highlighted element, on one of the allowedElements, or anywhere else. Return false to block the event, including the overlayClickBehavior it would trigger. Clicks on the popover and key presses are not reported.
allowedElements
type AllowedElements =
| string
| Element
| Array<string | Element>
| (() => Element[] | NodeListOf<Element> | null | undefined);
Selectors, elements, or a function returning elements. They stay clickable, sit above the overlay and take part in Tab navigation. Selectors and functions are evaluated again as the page changes, so elements that appear later are included. If one still sits under the overlay, set --driver-allowed-z-index or target its positioned wrapper. When the highlighted element is inside an allowed element, like an item in an open menu, it gets the driver-active-element-raised class and a ring instead of the cutout; see Theming.
overlayClickBehavior
"close" ends the tour, "nextStep" moves on, "none" does nothing. On an action step, "close" and "nextStep" shake the popover instead. "nextStep" does nothing while a step waits for its element. A function runs in every case.
How Clicks Are Handled
While a tour runs, only the highlighted element, allowedElements and the popover take pointer events. A press anywhere else belongs to the tour, and your app never sees it:
- Its
pointerdown,mousedown,pointerup,mouseup,click,touchstartandtouchendare stopped onwindowin the capture phase. Onlywindowcapture listeners added before the tour started still run. - Mouse events are also canceled, so focus stays where it was. Touch events are not, so scrolling works.
- A drag that starts in the highlighted element ends normally, wherever it is released.
The same goes for presses on an element with disableActiveInteraction, which also blocks the click that Enter or Space makes on it.
Only what the user does is stopped. Events your code dispatches, like element.click(), go through.
Missing Elements
| Situation | Option | What happens |
|---|---|---|
| The next element renders late | waitForElement: 3000 | The current step stays, with its popover in a waiting state, until the element appears or the time runs out |
| The element may not exist at all | skipMissingElement: true | The step is skipped in the direction of travel |
| The highlighted element is replaced | nothing | The step follows the new element matching its selector |
| The highlighted element is removed | onElementMissing | See below |
onElementMissing takes a preset or a function:
"stay"(default): the step stays where the element was."previous": go back one step."previousAction": go back to the last action step whose element is still on the page, or one step back if there is none.
With waitForElement set, a removed element first gets that long to come back. "previous" and "previousAction" also keep the current step when the next step’s waitForElement runs out, instead of showing that step without its element.
type ElementMissing =
| "stay"
| "previous"
| "previousAction"
| ElementMissingHook;
type ElementMissingHook = (
element: Element | undefined,
step: DriveStep,
opts: HookOpts & { cause: "removed" | "timeout" }
) => false | void;
A function is called with cause: "removed" when the highlighted element is gone, and decides what to do. It is called with cause: "timeout" when a step’s waitForElement runs out, with that step and its index; the step then shows without its element unless the function returns false or navigates.
Examples: Wait for Elements, Optional Steps, menus and slow loads.
Hooks
type DriverHook = (
element: Element | undefined,
step: DriveStep,
opts: HookOpts
) => void;
type HookOpts = {
config: Config;
state: State;
driver: Driver;
// Index of the active step. undefined in highlight().
index: number | undefined;
// Why the tour is ending. Only in the destroy hooks.
reason?: "done" | "close" | "escape" | "overlay" | "replaced" | "api";
// Aborts when the step is left. Only in onHighlightStarted and
// onHighlighted.
signal?: AbortSignal;
};
| Hook | Runs |
|---|---|
onHighlightStarted | Before a step’s element is highlighted |
onHighlighted | Once the highlight has settled on the element |
onDeselected | When a step is left, and when the tour ends |
onDestroyStarted | When the user tries to end the tour. The tour only ends if you call destroy() |
onDestroyed | After the tour has ended |
onPopoverRender | After the popover is added to the page, before it is positioned. Change its DOM here |
onNextClick, onPrevClick, onCloseClick | Instead of the button’s default action |
onDoneClick | Instead of onNextClick on the last step |
- On the last step the order is: the step’s
onDoneClick, the driver’sonDoneClick, the step’sonNextClick, the driver’sonNextClick. A driver-levelonDoneClicktherefore runs instead of a step’s ownonNextClickthere. - On an action step, pressing the disabled Next, the right arrow key or the overlay doesn’t run
onNextClick; completing the step does. - The click hooks replace the default. Call
moveNext(),movePrevious()ordestroy()yourself.onNextClickalso runs for the right arrow key,overlayClickBehavior: "nextStep",advanceOnandadvance(). indexis always the active step. Inside theonDeselectedthat runs between steps, that is the step being moved to.signalcleans up listeners for you:window.addEventListener("saved", onSaved, { signal }).destroy()does not runonDestroyStarted. Neither does a tour that is replaced by another instance.
Why a Tour Ended
onDestroyStarted, onDestroyed and the onDeselected that runs on destroy get opts.reason:
| Reason | Meaning |
|---|---|
"done" | Moved past the last step, including when the remaining steps were skipped |
"close" | The close button |
"escape" | The Escape key |
"overlay" | A click on the overlay |
"replaced" | Another driver instance started |
"api" | Your code called destroy(), or moveTo() / movePrevious() outside the steps |
A destroy() you call from a hook keeps the reason of the user action that started it. See Confirm Before Closing and Track Tour Analytics for examples.
State
driverObj.getState() returns the state, and hooks get it as opts.state.
type State = {
// Whether a tour or highlight is showing.
isInitialized?: boolean;
// Index, element and step that are active. No index in highlight().
activeIndex?: number;
activeElement?: Element;
activeStep?: DriveStep;
// Element and step that were active before.
previousElement?: Element;
previousStep?: DriveStep;
// The popover's DOM elements.
popover?: PopoverDOM;
};
PopoverDOM is described in Theming.
Hints Configuration
Passed to hints() from driver.js/hints. See the Hints guide for examples.
type HintsConfig = {
hints?: DriverHint[];
// Beacon defaults for every hint. A hint's own values win.
beacon?: HintBeacon;
// Text of the dismiss button. (default: "Got it")
buttonText?: string;
// Same meaning as in tours.
popoverClass?: string;
popoverOffset?: number;
// Dim the page while a hint is open, with its element cut out.
// (default: false)
overlay?: boolean;
// (defaults: "#000" and 0.7)
overlayColor?: string;
overlayOpacity?: number;
// Called when a hint opens, and when it is dismissed.
onOpen?: HintHook;
onDismiss?: HintHook;
// Runs instead of dismissing when the button is clicked.
onButtonClick?: HintHook;
};
type HintHook = (
element: Element,
hint: DriverHint,
opts: { config: HintsConfig; hints: Hints }
) => void;
type DriverHint = {
// A hint whose element is missing is skipped, and picked up on a
// later show().
element: string | Element | (() => Element);
// Used by open(), dismiss() and restore(), and to save dismissals.
// (default: the hint's index)
id?: string;
beacon?: HintBeacon;
popover?: {
title?: string;
description?: string;
side?: "top" | "right" | "bottom" | "left";
align?: "start" | "center" | "end";
popoverClass?: string;
// The dismiss button. (default: true)
showButton?: boolean;
buttonText?: string;
onButtonClick?: HintHook;
onPopoverRender?: (
popover: PopoverDOM,
opts: { hint: DriverHint; hints: Hints }
) => void;
};
// Run instead of the hooks in HintsConfig.
onOpen?: HintHook;
onDismiss?: HintHook;
data?: Record<string, any>;
};
type HintBeacon = {
// Edge of the element the beacon sits on, and where along it.
// (defaults: "top" and "end")
side?: "top" | "right" | "bottom" | "left";
align?: "start" | "center" | "end";
// Move the beacon by this many pixels. Positive is right and down.
offsetX?: number;
offsetY?: number;
// Pulse. Off for users who prefer reduced motion. (default: true)
animate?: boolean;
className?: string;
};
Checklist Configuration
Passed to checklist() from driver.js/checklist. See the Checklists guide for examples.
type ChecklistConfig = {
// Identifies the checklist in events.
id: string;
items: ChecklistItem[];
// (defaults: "Get started", none, the title)
title?: string;
description?: string;
launcherText?: string;
// Shown instead once every item is done.
completeTitle?: string;
completeDescription?: string;
completeLauncherText?: string;
// {{done}}, {{total}}, {{remaining}} and {{percent}} are replaced.
// (default: "{{done}} of {{total}}")
progressText?: string;
// The count on the launcher. "" hides it.
// (default: "{{done}}/{{total}}")
launcherProgressText?: string;
// false hides the launcher. Open the panel yourself with open() or
// toggle().
// (default: true)
launcher?: boolean;
// (default: "bottom-right")
position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
// Distance from the screen edges, in pixels. (default: 20, 12 on phones)
offset?: { x?: number; y?: number };
className?: string;
// Let users tick and untick items with the check circle.
// (default: false)
allowManualComplete?: boolean;
// Ids of the items that are already done.
completed?: string[];
// Called on every change.
onProgress?: (progress: {
completed: string[];
done: number;
total: number;
}) => void;
// Called when an item is ticked, and once when all are.
onItemComplete?: (
item: ChecklistItem,
opts: { checklist: Checklist }
) => void;
onComplete?: (opts: { checklist: Checklist }) => void;
// Called with every event. See the Checklists guide for the types.
onEvent?: (event: ChecklistEvent) => void;
};
type ChecklistItem = {
// Saved progress is a list of these, so keep them stable.
id: string;
// HTML is allowed in both.
title: string;
description?: string;
// What a click does. A tour ticks the item when the user finishes it,
// a link or an action ticks it on click.
tour?: DriveStep[] | Config | Driver;
href?: string;
action?: (item: ChecklistItem, opts: { checklist: Checklist }) => void;
// Ticks the item once it returns true, instead of the rules above.
completeWhen?: () => boolean;
// Overrides the checklist's allowManualComplete.
allowManualComplete?: boolean;
data?: Record<string, any>;
};
driver.js