Configuration

Driver.js is built to be highly configurable. You can configure the driver globally, or per step. You can also configure the driver on the fly, while it’s running.

Configuration, steps, and state belong to the specific driver() instance you set them on. Each call to driver() is independent, so you can keep several instances on the same page and configuring one never affects another. Only one instance is shown at a time: driving or highlighting with one closes any other active instance.

Driver.js is written in TypeScript. Configuration options are mostly self-explanatory. Also, if you’re using an IDE like WebStorm or VSCode, you’ll get autocomplete and documentation for all the configuration options.

Driver Configuration

You can configure the driver globally by passing the configuration object to the driver call or by using the setConfig method. Given below are some of the available configuration options.

type Config = {
  // Array of steps to highlight. You should pass
  // this when you want to setup a product tour.
  steps?: DriveStep[];

  // Whether to animate the product tour. (default: true)
  animate?: boolean;
  // Duration of the transition animation in milliseconds. Controls both the
  // speed of the stage moving between steps and the overlay/popover fade-in.
  // Only applies when `animate` is true. (default: 400)
  duration?: number;
  // Overlay color. (default: black)
  // This is useful when you have a dark background
  // and want to highlight elements with a light
  // background color.
  overlayColor?: string;
  // Whether to smooth scroll to the highlighted element. (default: false)
  smoothScroll?: boolean;
  // Whether to allow closing the popover by clicking on the backdrop. (default: true)
  allowClose?: boolean;
  // Whether to allow scrolling the page while the driver is active.
  // Set to false to lock body scrolling for the duration of the tour. (default: true)
  allowScroll?: boolean;
  // Opacity of the backdrop. (default: 0.5)
  overlayOpacity?: number;
  // What to do when the overlay backdrop is clicked.
  // Possible options are 'close', 'nextStep', 'none', or a custom function. (default: 'close')
  // Use 'none' to ignore overlay clicks while Escape and the close button still work.
  overlayClickBehavior?:
    | "close"
    | "nextStep"
    | "none"
    | ((
        element?: Element,
        step: DriveStep,
        options: { config: Config; state: State; driver: Driver; index: number | undefined }
      ) => void);
  // Distance between the highlighted element and the cutout. (default: 10)
  stagePadding?: number;
  // Radius of the cutout around the highlighted element. (default: 5)
  stageRadius?: number;

  // Whether to allow keyboard navigation. (default: true)
  // Arrow keys are ignored when their button is hidden or disabled,
  // and Escape is ignored when the close button is disabled.
  allowKeyboardControl?: boolean;

  // Whether to disable interaction with the highlighted element. (default: false)
  // Can be configured at the step level as well
  disableActiveInteraction?: boolean;

  // Advance the tour when the highlighted element is clicked, as if the next
  // button was pressed; onNextClick and onDoneClick still apply. The element's
  // own click behavior runs normally. Has no effect on steps where
  // disableActiveInteraction blocks clicks. Can be configured at the step
  // level. (default: false)
  advanceOnClick?: boolean;

  // Skip a step whose target element is specified but missing from the DOM,
  // moving on in the direction of travel instead of showing the centered
  // fallback popover. Steps without an element are intentional centered steps
  // and are never skipped. Can be configured at the step level. (default: false)
  skipMissingElement?: boolean;

  // Wait up to this many milliseconds for a step's element to appear before
  // treating it as missing (centered fallback popover, or a skip when
  // skipMissingElement is set). The current step stays highlighted, with its
  // popover hidden, while waiting. Useful when the next element is rendered on demand, e.g. inside
  // a modal that the previous step's click opens. Can be configured at the
  // step level. (default: 0, off)
  waitForElement?: number;

  // If you want to add custom class to the popover
  popoverClass?: string;
  // Distance between the popover and the highlighted element. (default: 10)
  popoverOffset?: number;
  // Array of buttons to show in the popover. Defaults to ["next", "previous", "close"]
  // for product tours and [] for single element highlighting.
  showButtons?: AllowedButtons[];
  // Array of buttons to disable. This is useful when you want to show some of the
  // buttons, but disable some of them.
  disableButtons?: AllowedButtons[];

  // Whether to show the progress text in popover. (default: false)
  showProgress?: boolean;
  // Template for the progress text. You can use the following placeholders in the template:
  //  - {{current}}: The current step number
  //  - {{total}}: Total number of steps
  progressText?: string;

  // Text to show in the buttons. `doneBtnText`
  // is used on the last step of a tour.
  nextBtnText?: string;
  prevBtnText?: string;
  doneBtnText?: string;

  // Screen reader label of the close button. Defaults to "Close".
  closeBtnLabel?: string;

  // Called after the popover is rendered.
  // PopoverDOM is an object with references to
  // the popover DOM elements such as buttons
  // title, descriptions, body, container etc.
  onPopoverRender?: (
    popover: PopoverDOM,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;

  // Hooks to run before and after highlighting
  // each step. Each hook receives the following
  // parameters:
  //   - element: The target DOM element of the step
  //   - step: The step object configured for the step
  //   - options.config: The current configuration options
  //   - options.state: The current state of the driver
  //   - options.driver: Current driver object
  //   - options.index: Index of the currently active step
  onHighlightStarted?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onHighlighted?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onDeselected?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined; reason?: DestroyReason }
  ) => void;

  // Hooks to run before and after the driver
  // is destroyed. Each hook receives
  // the following parameters:
  //   - element: Currently active element
  //   - step: The step object configured for the currently active
  //   - options.config: The current configuration options
  //   - options.state: The current state of the driver
  //   - options.driver: Current driver object
  //   - options.index: Index of the currently active step
  //   - options.reason: Why the tour is ending
  //       "done"     moved past the last step
  //       "close"    the close button
  //       "escape"   the escape key
  //       "overlay"  a click on the overlay
  //       "replaced" another driver instance started
  //       "api"      destroy() or navigation from your own code
  //     A destroy() you call from a hook (e.g. confirming in
  //     onDestroyStarted) keeps the reason of the action that
  //     started it. onDeselected also gets it when it runs on destroy.
  onDestroyStarted?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined; reason: DestroyReason }
  ) => void;
  onDestroyed?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined; reason: DestroyReason }
  ) => void;

  // Hooks to run on button clicks. Each hook receives
  // the following parameters:
  //   - element: The current DOM element of the step
  //   - step: The step object configured for the step
  //   - options.config: The current configuration options
  //   - options.state: The current state of the driver
  //   - options.driver: Current driver object
  //   - options.index: Index of the currently active step
  onNextClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onPrevClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onCloseClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  // Runs when the done button (the next button on the
  // last step of a tour) is clicked. When provided, it
  // runs instead of `onNextClick` on the last step.
  onDoneClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
};

Note: By overriding onNextClick, and onPrevClick hooks you control the navigation of the driver. This means that user won’t be able to navigate using the buttons and you will have to either call driverObj.moveNext() or driverObj.movePrevious() to navigate to the next/previous step.

You can use this to implement custom logic for navigating between steps. This is also useful when you are dealing with dynamic content and want to highlight the next/previous element based on some logic.

onNextClick and onPrevClick hooks can be configured at the step level as well. When configured at the driver level, you control the navigation for all the steps. When configured at the step level, you control the navigation for that particular step only.

onDoneClick lets you detect when the user finishes the tour by clicking the done button on the last step. When provided, it runs instead of onNextClick on the last step, and Driver.js won’t destroy the tour automatically; you control teardown by calling driverObj.destroy() yourself. Like the other click hooks, it can be configured at the driver or step level.

options.index: Every hook receives the zero-based index of the currently active step in options.index (equivalent to driverObj.getActiveIndex()), or undefined when driving a single highlight rather than a steps array. Note that index always reflects the active step, so inside onDeselected (which fires for the step being left during a transition) it points at the step being moved to, not the one being deselected.

options.reason: onDestroyStarted, onDestroyed and the onDeselected that runs when the tour ends receive why it ended: "done" (moved past the last step, including when the remaining steps are skipped as missing), "close", "escape", "overlay", "replaced" (another driver instance started) or "api" (destroy(), or a moveTo() / movePrevious() that left the steps, from your own code). It is not set on the other hooks, or on the onDeselected that runs between steps. A destroy() you call from a hook (onDestroyStarted, onCloseClick, onNextClick / onDoneClick on the last step, an overlayClickBehavior function) keeps the reason of the user action that started it. This hook only asks when the user leaves early:

onDestroyStarted: (el, step, { reason }) => {
  if (reason === "done" || confirm("Leave?")) {
    driverObj.destroy();
  }
};

The type is exported as DestroyReason.

Popover Configuration

The popover is the main UI element of Driver.js. It’s the element that highlights the target element, and shows the step content. You can configure the popover globally, or per step. Given below are some of the available configuration options.

type Popover = {
  // Title and descriptions shown in the popover.
  // You can use HTML in these. Also, you can
  // omit one of these to show only the other.
  title?: string;
  description?: string;

  // Which side of the target element the popover is
  // placed on. Auto-flips to the opposite side when it
  // doesn't fit the viewport. (default: "bottom")
  side?: "top" | "right" | "bottom" | "left";
  // How the popover is aligned along that side. "start"
  // lines its leading edge up with the element, "center"
  // centers it, and "end" lines up the trailing edges.
  // (default: "start")
  align?: "start" | "center" | "end";

  // Array of buttons to show in the popover.
  // When highlighting a single element, there
  // are no buttons by default. When showing
  // a tour, the default buttons are "next",
  // "previous" and "close".
  showButtons?: ("next" | "previous" | "close")[];
  // An array of buttons to disable. This is
  // useful when you want to show some of the
  // buttons, but disable some of them.
  disableButtons?: ("next" | "previous" | "close")[];

  // Text to show in the buttons. `doneBtnText`
  // is used on the last step of a tour.
  nextBtnText?: string;
  prevBtnText?: string;
  doneBtnText?: string;

  // Screen reader label of the close button. Defaults to "Close".
  closeBtnLabel?: string;

  // Whether to show the progress text in popover.
  showProgress?: boolean;
  // Template for the progress text. You can use
  // the following placeholders in the template:
  //   - {{current}}: The current step number
  //   - {{total}}: Total number of steps
  // Defaults to following if `showProgress` is true:
  //   - "{{current}} of {{total}}"
  progressText?: string;

  // Custom class to add to the popover element.
  // This can be used to style the popover.
  popoverClass?: string;

  // Hook to run after the popover is rendered.
  // You can modify the popover element here.
  // Parameter is an object with references to
  // the popover DOM elements such as buttons
  // title, descriptions, body, etc.
  onPopoverRender?: (
    popover: PopoverDOM,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;

  // Callbacks for button clicks. You can use
  // these to add custom behavior to the buttons.
  // Each callback receives the following parameters:
  //   - element: The current DOM element of the step
  //   - step: The step object configured for the step
  //   - options.config: The current configuration options
  //   - options.state: The current state of the driver
  //   - options.driver: Current driver object
  //   - options.index: Index of the currently active step
  onNextClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onPrevClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onCloseClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  // Runs instead of `onNextClick` when the done button
  // (the next button on the last step) is clicked.
  onDoneClick?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
};

Drive Step Configuration

Drive step is the configuration object passed to the highlight method or the steps array of the drive method. You can configure the popover and the target element for each step. Given below are some of the available configuration options.

type DriveStep = {
  // The target element to highlight.
  // This can be a DOM element,
  // a function that returns a DOM Element, or a CSS selector.
  // If this is a selector, the first matching
  // element will be highlighted.
  element?: Element | string | (() => Element);

  // The popover configuration for this step.
  // Look at the Popover Configuration section
  popover?: Popover;

  // Whether to disable interaction with the highlighted element. (default: false)
  disableActiveInteraction?: boolean;

  // Advance the tour when this step's highlighted element is clicked.
  // Overrides the driver-level option for this step. (default: false)
  advanceOnClick?: boolean;

  // Skip this step when its target element is specified but missing from the
  // DOM. Overrides the driver-level option for this step. (default: false)
  skipMissingElement?: boolean;

  // Wait up to this many milliseconds for this step's element to appear before
  // treating it as missing. Overrides the driver-level option. (default: 0, off)
  waitForElement?: number;

  // Arbitrary data that you can pass to the step in order to support complex custom logic in hooks.
  data?: Record<string, any>;

  // Callback when the current step is deselected,
  // about to be highlighted or highlighted.
  // Each callback receives the following parameters:
  //   - element: The current DOM element of the step
  //   - step: The step object configured for the step
  //   - options.config: The current configuration options
  //   - options.state: The current state of the driver
  //   - options.driver: Current driver object
  //   - options.index: Index of the currently active step
  //   - options.reason: Why the tour ended, only on the
  //     onDeselected that runs on destroy (see Driver Configuration)
  onDeselected?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined; reason?: DestroyReason }
  ) => void;
  onHighlightStarted?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
  onHighlighted?: (
    element?: Element,
    step: DriveStep,
    options: { config: Config; state: State; driver: Driver; index: number | undefined }
  ) => void;
};

Hints Configuration

Hints are configured through the hints() factory from the driver.js/hints entry. See the Hints guide for an introduction and examples; the full options are given below.

type HintsConfig = {
  // Array of hints to show. See the Hint
  // Configuration section below for the format.
  hints?: DriverHint[];

  // Beacon defaults applied to every hint;
  // a hint's own beacon values win.
  beacon?: HintBeacon;

  // Text of the dismiss button. (default: "Got it")
  buttonText?: string;

  // Custom class and offset for the hint popovers,
  // same meaning as in tours.
  popoverClass?: string;
  popoverOffset?: number;

  // Dim the page while a hint is open, with the hint's
  // element cut out like a tour step. The popover then
  // anchors to the element instead of the beacon, the
  // open hint's beacon steps aside, and the other
  // beacons wait under the dim. Clicking the dimmed
  // page closes the hint. (default: false)
  overlay?: boolean;
  // Color and opacity of the dim. (defaults: "#000" and 0.7)
  overlayColor?: string;
  overlayOpacity?: number;

  // Called when a hint popover is opened, and when a
  // hint is dismissed (via the button or `dismiss()`).
  // Each hook receives the following parameters:
  //   - element: The hint's target DOM element
  //   - hint: The hint object
  //   - options.config: The hints configuration
  //   - options.hints: The hints instance
  onOpen?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;
  onDismiss?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;

  // Runs instead of dismissing when the built-in button is clicked,
  // like a tour's onNextClick takes over the default advance. Call
  // options.hints.dismiss(hint.id) yourself to also remove the hint.
  // Can be configured per hint as well.
  onButtonClick?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;
};

Hint Configuration

Each entry of the hints array describes one hint: the element it points at, the beacon that sits on it, and the popover that opens on click.

type DriverHint = {
  // The element the hint points at. This can be a DOM
  // element, a function that returns a DOM element, or
  // a CSS selector. A hint whose element is missing is
  // skipped, and picked up on the next show() if the
  // element has appeared since.
  element: Element | string | (() => Element);

  // Stable identity used by open/dismiss/restore and
  // passed to the hooks; useful for persisting
  // dismissals. Defaults to the hint's index.
  id?: string;

  // Where the beacon sits on the element's box, and
  // how it looks.
  beacon?: {
    // Edge of the element the beacon sits on. (default: "top")
    side?: "top" | "right" | "bottom" | "left";
    // Position along that edge. (default: "end")
    align?: "start" | "center" | "end";
    // Nudge the beacon in pixels from its anchor point.
    // Positive moves right/down, negative left/up.
    // (default: 0)
    offsetX?: number;
    offsetY?: number;
    // Whether the beacon pulses. The pulse also pauses
    // automatically for users who prefer reduced
    // motion. (default: true)
    animate?: boolean;
    // Custom class for the beacon, e.g. to scope the
    // --driver-hint-size and --driver-hint-color
    // CSS variables to it.
    className?: string;
  };

  // The popover that opens when the beacon is clicked.
  // Rendered exactly like a tour popover.
  popover?: {
    title?: string;
    description?: string;
    side?: "top" | "right" | "bottom" | "left";
    align?: "start" | "center" | "end";
    popoverClass?: string;

    // The dismiss button. Hide it for hints you only
    // dismiss from code. (default: true)
    showButton?: boolean;
    // Overrides the instance-level buttonText.
    buttonText?: string;
    // Overrides the instance-level onButtonClick.
    onButtonClick?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;

    // Hook to run after the popover is rendered,
    // same as in tours but with the hint and the
    // hints instance in the options.
    onPopoverRender?: (popover: PopoverDOM, options: { hint: DriverHint; hints: Hints }) => void;
  };

  // Hint-level hooks, taking precedence over the
  // instance-level ones.
  onOpen?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;
  onDismiss?: (element: Element, hint: DriverHint, options: { config: HintsConfig; hints: Hints }) => void;

  // Arbitrary data to carry along, available wherever
  // the hint object is.
  data?: Record<string, any>;
};

Checklist Configuration

Checklists are configured through the checklist() factory from the driver.js/checklist entry. See the Checklists guide for an introduction and examples; the full options are given below.

type ChecklistConfig = {
  // Identifies the checklist in events.
  id: string;

  // Array of items. See the Checklist Item
  // Configuration section below for the format.
  items: ChecklistItem[];

  // Text in the panel header, below the title, and on the
  // launcher button. (defaults: "Get started", none, the title)
  title?: string;
  description?: string;
  launcherText?: string;

  // Shown instead of the title, description and launcher
  // text once every item is done, and swapped back if an
  // item is unticked. An empty completeDescription hides
  // the description.
  completeTitle?: string;
  completeDescription?: string;
  completeLauncherText?: string;

  // Progress text next to the bar; {{done}}, {{total}},
  // {{remaining}} and {{percent}} are replaced.
  // (default: "{{done}} of {{total}}")
  progressText?: string;

  // The count on the launcher, with the same placeholders.
  // An empty string hides it. (default: "{{done}}/{{total}}")
  launcherProgressText?: string;

  // false hides the floating launcher, for pages that open the panel
  // from their own button with open() or toggle(). (default: true)
  launcher?: boolean;

  // Corner of the screen. In the top corners the panel
  // opens below the launcher. (default: "bottom-right")
  position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";

  // Distance in pixels from the screen edges.
  // (default: 20, or 12 on screens narrower than 480px)
  offset?: { x?: number; y?: number };

  // Extra class on the widget.
  className?: string;

  // Turns the check circle into a button, so users can tick
  // items off, or untick them, themselves. (default: false)
  allowManualComplete?: boolean;

  // Ids of the items that are already done, for progress
  // you saved earlier.
  completed?: string[];

  // Called on every change with the ids of the done items
  // (including ids no longer in `items`) and the count.
  onProgress?: (progress: { completed: string[]; done: number; total: number }) => void;

  // Called when an item is ticked, and once when every
  // item is done.
  onItemComplete?: (item: ChecklistItem, options: { checklist: Checklist }) => void;
  onComplete?: (options: { checklist: Checklist }) => void;

  // Called with every checklist event: shown, hidden, opened,
  // closed, item_started, item_completed, item_uncompleted,
  // tour_ended, completed and reset. tour_ended carries the
  // tour's destroy reason.
  onEvent?: (event: {
    kind: "checklist";
    id: string;
    type: string;
    itemId?: string;
    reason?: DestroyReason;
    timestamp: number;
  }) => void;
};

Checklist Item Configuration

Each entry of the items array is one task. Clicking it starts its tour, follows its link or runs its action.

type ChecklistItem = {
  // Stable identity, used for progress. Keep it the
  // same when you reword or reorder items.
  id: string;

  // HTML is allowed, like in popovers.
  title: string;
  description?: string;

  // A tour to run: steps, a driver configuration or a
  // driver() instance. The item is ticked when the user
  // finishes the tour, not when they close it early.
  tour?: DriveStep[] | Config | Driver;

  // A link to follow. The item is ticked on click.
  href?: string;

  // Your own code to run. The item is ticked afterwards.
  action?: (item: ChecklistItem, options: { checklist: Checklist }) => void;

  // Ticks the item once it returns true. Checked on show(),
  // refresh() and after the item's tour or action, and it
  // replaces the default ticking above.
  completeWhen?: () => boolean;

  // Overrides the checklist's allowManualComplete for this item.
  allowManualComplete?: boolean;

  // Your own data, available on the item in hooks.
  data?: Record<string, any>;
};

State

You can access the current state of the driver by calling the getState method. It’s also passed to the hooks and callbacks.

type State = {
  // Whether the driver is currently active or not
  isInitialized?: boolean;

  // Index of the currently active step if using
  // as a product tour and have configured the
  // steps array.
  activeIndex?: number;
  // DOM element of the currently active step
  activeElement?: Element;
  // Step object of the currently active step
  activeStep?: DriveStep;

  // DOM element that was previously active
  previousElement?: Element;
  // Step object of the previously active step
  previousStep?: DriveStep;

  // DOM elements for the popover i.e. including
  // container, title, description, buttons etc.
  popover?: PopoverDOM;
};