Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Driver Js Laravel Package

amjadiqbal/laravel-driver-js

A Laravel wrapper for Driver.js that adds guided product tours and onboarding highlights to your Blade views. Define tour steps in PHP, publish the config, and highlight page elements with simple helpers—no custom JavaScript required.

View on GitHub
Deep Wiki
Context7

Getting Started

Install:

composer require amjadiqbal/laravel-driver-js
php artisan vendor:publish --tag=driver-js-config   # inspect config/driver-js.php

Requirements are strict in v1.0.0: Laravel 12 or 13, PHP 8.3+. If you're still on L10/L11 or PHP 8.2, stay on the abandoned 0.1.0 branch (which doesn't work with Driver.js 1.x anyway) — there is no middle path.

Look here first, in this order:

  1. config/driver-js.php — v1.0.0 moved everything around. Driver.js options now live under defaults, CDN/asset settings under assets. If you're porting a 0.1.x config, this is where nothing will line up.
  2. php artisan about — the new "Driver.js tours" section confirms the resolved Driver.js version, whether the CDN or local build is in use, and your asset mode. This is your fastest smoke test after deploy.
  3. Your layout's <head>/end-of-<body> — you must add @driverJsAssets yourself. It is not auto-injected.

First use case — a welcome tour:

{{-- resources/views/layouts/app.blade.php --}}
    @driverJsAssets
</body>
use AmjadIqbal\DriverJs\Facades\Driver;

Driver::tour('welcome')
    ->once('welcome-v1')
    ->step('#sidebar', 'Your navigation', 'Everything starts here.')
    ->step('#search', 'Search', 'Find anything fast.')
    ->showProgress()
    ->overlayOpacity(0.6);

That's the whole loop: register in a service provider (or a Livewire component's mount), render the directive once, and the tour auto-starts for first-time visitors thanks to once().

Implementation Patterns

Where to register tours. Tours are declared in PHP and executed in the browser, so registration belongs in a ServiceProvider::boot() for global tours, or in a Livewire component's mount() when the tour is conditional on the page. Registering the same tour name twice in one request is the most common source of "it starts twice" bugs — pick one home per tour.

The three trigger styles. v1.0.0 gives you one registry and three ways to fire a tour:

{{-- 1. Plain HTML, zero JS --}}
<button data-driver-start="welcome">Replay tour</button>

{{-- 2. Alpine --}}
<button x-on:click="$dispatch('driver-js:start', { tour: 'welcome' })">Replay</button>
// 3. Livewire — either dispatch manually…
$this->dispatch('driver-js:start', tour: 'welcome');

// …or use the trait
use AmjadiIqbal\DriverJs\Livewire\StartsTours;

The data-driver-start attribute is the pattern I'd default to. It's a plain attribute, survives Blade component composition, and needs no JS bundle of your own.

Deferred/opt-in tours. manual() (alias autoStart(false)) registers a tour without firing it. Reach for this whenever the tour is behind a button, a settings toggle, or a "show me around" link — otherwise every page load nags the user.

One-off element highlighting. highlight('#element') is the right tool for a single callout, and it's meaningfully cheaper than a one-step tour. Use it for "new feature" badges and inline hints; use tour() when there's narrative sequence, progress, and next/back buttons.

Browser-side hooks. Ten Driver.js hooks are exposed via on($hook, 'window.fnName'). The string is resolved in the browser, so the function must exist on window by the time the hook fires:

Driver::tour('onboarding')
    ->on('onHighlightStarted', 'window.trackStep')
    ->on('onDestroyed', 'window.markTourComplete');

This is the correct integration point for analytics — hook onHighlightStarted and onDestroyed rather than trying to poll tour state.

Controlling a running tour. The PHP builder's drive(), destroy(), moveNext(), and movePrevious() are gone in v1.0.0 — they queued an action the Blade component never read, so they silently did nothing. The replacement is JS-side:

LaravelDriverJs.active()?.moveNext();
LaravelDriverJs.active()?.destroy();

If you have 0.1.x code calling those builder methods, it was already broken; deleting the calls changes nothing observable.

Livewire wire:navigate. Tours survive SPA navigation, but registration does not — a tour registered in a full page load won't exist after a wire:navigate. Register in a persistent component, in a #[On] handler, or listen for livewire:navigated and re-register. Use the StartsTours trait if you want this handled for you.

Gotchas and Tips

The CDN is now real, and pinned. v1.0.0 loads Driver.js 1.10.2 from jsDelivr with Subresource Integrity. The 0.1.0 default URL (driver.js/dist/driver.min.js) 404s — if you have a stale cached config with a hand-written CDN path, you'll get a silent no-op. Delete the published config and re-publish after upgrading.

CSP setups need nothing extra, but only if you use Vite's nonce. @driverJsAssets emits a nonce automatically when Vite::useCspNonce() is set. If you emit nonces some other way (a middleware that swaps a placeholder, a nonce from a header), you'll need to make sure Vite::useCspNonce() reflects it — otherwise your script-src blocks the tour with a console error and nothing else.

Tour text is escaped via Js::from(). This was a real XSS hole in 0.1.0 and is fixed. Consequence: you cannot inject HTML into tour titles/descriptions. If a step description genuinely needs markup, that's not supported — put the markup in the anchored DOM instead and keep tour copy plain.

once() keys are your versioning mechanism. The key is stored in localStorage and is per-browser, not per-user. Bump the key (welcome-v1 → welcome-v2) to re-show an updated tour to everyone. During development you'll be bumping it constantly — or just clear localStorage in DevTools. Don't forget this: "the tour won't show" after editing is almost always a stale once() key.

Validation is on your side now. Sides, alignments, button sets, and hook names are validated server-side. A typo in ->on('onHighlighStarted', ...) throws instead of silently never firing — but that also means a bad option will 500 the page rather than degrade, so test tour registration in staging, not just in the browser.

Deprecated but working: addStep(), defineSteps(), opacity(), onHighlighting(). These still function in v1.0.0 as shims for step(), steps(), overlayOpacity(), and on('onHighlightStarted', ...). They exist for a clean upgrade path and will be removed in a future major. Mechanical rename — do it in one pass with a find-and-replace rather than leaving a mixed codebase.

Self-hosting. assets.cdn = false disables the jsDelivr load and leaves asset emission to you. Pair it with your own Vite entry that imports driver.js, and keep @driverJsAssets for everything else (it still handles the once-per-request dedupe and nonce). Note that the SRI hashes only apply to the CDN path.

Debugging checklist, in order: does php artisan about show a Driver.js version? → is @driverJsAssets in the layout and rendered once (not zero, not twice)? → does the tour name in data-driver-start match the Driver::tour('...') string exactly (case-sensitive)? → is a once() key blocking it? → does the anchor selector exist in the DOM at the moment the tour starts (a manual() tour fired before Livewire hydrates will find nothing)?

Bundle it or don't, but decide deliberately. The pinned CDN + SRI is the path of least resistance and is fine for most apps. Self-host when you have data-residency requirements, offline/air-gapped deployments, or a CSP that disallows external origins outright — not merely to shave a request.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums