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 somethingadvanceOn: "click", "input", "change", …
Move on only when the result is rightadvanceOn: { event, when }
Accept one gesture on the element and block other clicksadvanceOn: { event, strict: true }
Take away the Next button so the user has to actpopover.instruction
Let the user use something outside the element, like a menuallowedElements
Let the user look but not touchdisableActiveInteraction: true
Keep hover and tooltips, block clicksdisableActiveInteraction: "clicks"
Decide per click, or react to a wrong clickonInteraction
Choose what a click on the dimmed page doesoverlayClickBehavior

advanceOn

type AdvanceOnEvent = {
  event: string | string[];
  when?: (
    element: Element,
    step: DriveStep,
    opts: HookOpts & { event: Event }
  ) => boolean;
  strict?: boolean;
};
  • event is any DOM event name that reaches the highlighted element, or a list of them.
  • when runs after your app has handled the event. The step completes only when it returns true.
  • strict: true makes 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).
  • false on a step turns off the driver’s advanceOn for 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, touchstart and touchend are stopped on window in the capture phase. Only window capture 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

SituationOptionWhat happens
The next element renders latewaitForElement: 3000The 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 allskipMissingElement: trueThe step is skipped in the direction of travel
The highlighted element is replacednothingThe step follows the new element matching its selector
The highlighted element is removedonElementMissingSee 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;
};
HookRuns
onHighlightStartedBefore a step’s element is highlighted
onHighlightedOnce the highlight has settled on the element
onDeselectedWhen a step is left, and when the tour ends
onDestroyStartedWhen the user tries to end the tour. The tour only ends if you call destroy()
onDestroyedAfter the tour has ended
onPopoverRenderAfter the popover is added to the page, before it is positioned. Change its DOM here
onNextClick, onPrevClick, onCloseClickInstead of the button’s default action
onDoneClickInstead of onNextClick on the last step
  • On the last step the order is: the step’s onDoneClick, the driver’s onDoneClick, the step’s onNextClick, the driver’s onNextClick. A driver-level onDoneClick therefore runs instead of a step’s own onNextClick there.
  • 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() or destroy() yourself. onNextClick also runs for the right arrow key, overlayClickBehavior: "nextStep", advanceOn and advance().
  • index is always the active step. Inside the onDeselected that runs between steps, that is the step being moved to.
  • signal cleans up listeners for you: window.addEventListener("saved", onSaved, { signal }).
  • destroy() does not run onDestroyStarted. 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:

ReasonMeaning
"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>;
};