Events
React to Tour and Hints lifecycle events, and cancel the ones that matter.
Driver.js exposes its lifecycle through callbacks, which a server-rendered Tour has no place to attach.
UX Driver bridges them into DOM events on document instead, so application JavaScript can observe a Tour
without ever constructing one.
The complete list — nine Tour events, six Hints events, every detail payload — is in the
Stimulus reference. This page is about what to do with them.
Blocking a navigation
Five Tour events are cancelable: ux-driver:next, ux-driver:previous, ux-driver:close,
ux-driver:done, and ux-driver:destroy-started. Calling preventDefault() on one stops the default
behavior the controller would otherwise run — moveNext(), movePrevious(), destroy(), or completion.
That makes a Step into a gate:
document.addEventListener('ux-driver:next', (event) => {
const { tourId, index } = event.detail
if (tourId === 'checkout-tour' && index === 1 && !form.reportValidity()) {
event.preventDefault()
}
})
The Tour stays where it is, the form shows its own validation, and no Driver.js API was touched.
Reacting to progress
The non-cancelable events are for observation — analytics, lazy loading, syncing another panel:
document.addEventListener('ux-driver:highlighted', (event) => {
const { tourId, index, element } = event.detail
analytics.track('tour_step_viewed', { tour: tourId, step: index })
element.scrollIntoView({ block: 'nearest' })
})
Every Tour event after connect carries the same shape: {tourId, index, step, element, driver}. The
driver handle is the live Driver.js instance, which is the escape hatch for anything the bundle does not
serialize.
Hints
Hints events are never cancelable — they report what happened, they do not gate it:
document.addEventListener('ux-driver:hint-dismiss', (event) => {
const { groupId, hintId } = event.detail
fetch('/preferences/hints', {
method: 'POST',
body: JSON.stringify({ group: groupId, hint: hintId }),
})
})
That listener is also how a dismissal is made to last: the bundle does not persist dismissed Hints, so recording it server-side and re-rendering the group without that Hint is the durable version.
Timing
ux-driver:pre-connect fires before the Driver.js instance exists and carries the configuration about to
be used — mutate it there if a Tour needs a runtime value. ux-driver:connect fires once the instance is
built. ux-driver:empty fires when a controller connects with nothing to show, which usually means a
selector matched no element.