Skip to content

Onboarding · Open source

Laravel Driver.js

Build Driver.js product tours in PHP and render them with one Blade component.

Laravel 12 and 13 PHP 8.3+ v1.0.0 Free · MIT
Laravel Driver.js: Build Driver.js product tours in PHP and render them with one Blade component.

What it solves

Adding Driver.js to a Laravel app usually means hand-writing a script for each page, remembering who has already seen the tour, and wiring it to Livewire yourself.

You define tours and steps in PHP, put <x-driver-js> in the view, and start a tour from a button, Alpine, Livewire or JavaScript. once() shows a tour only the first time a visitor sees it, with no JavaScript to write and no npm build step.

  • Tours and steps built in PHP with Driver.js's own option names
  • Invalid sides, alignments, buttons and hook names rejected before they reach the browser
  • once() auto-starts a tour only the first time a visitor sees it
  • Start a tour from a button, Alpine, a Livewire component or JavaScript
  • Tour text escaped with Js::from(), and Driver.js loaded from a pinned CDN URL with SRI hashes
  • Scripts carry Laravel's CSP nonce, and Driver.js can be bundled with Vite instead
A Laravel billing dashboard dimmed behind a Driver.js tour on step 3 of 4: a popover titled Overdue invoices, with Back and Next buttons, points at the highlighted Overdue invoices card.
A Laravel billing dashboard dimmed behind a Driver.js tour on step 3 of 4: a popover titled Overdue invoices, with Back and Next buttons, points at the highlighted Overdue invoices card.

Install

Requires PHP 8.3+ and Laravel 12 and 13.

composer require amjadiqbal/laravel-driver-js

Usage

use AmjadIqbal\DriverJS\Facades\Driver;

// In a controller: a welcome tour that new users see once
$tour = Driver::tour('welcome')
    ->once('welcome-v1')
    ->step(null, 'Welcome to Acme', 'A 30-second tour of where everything lives.')
    ->step('#revenue', 'Monthly revenue', 'Updated every hour.', ['side' => 'bottom']);

return view('dashboard', ['tour' => $tour]);

// In the view: <x-driver-js :tour="$tour" />

Setup

The service provider and the Driver facade are registered automatically. Publishing the config is only needed to change the defaults.

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

A tour in Blade

Pass a tour built in PHP with <x-driver-js :tour="$tour" />, or write the Driver.js steps in the view. The first <x-driver-js> on a page prints the Driver.js stylesheet, script and a small runtime. Add @driverJsAssets to your <head> to print them there instead.

<x-driver-js name="settings" :steps="[
    ['element' => '#profile', 'popover' => ['title' => 'Your profile', 'description' => 'Name, photo and email.']],
    ['element' => '#billing', 'popover' => ['title' => 'Billing', 'description' => 'Plans and invoices.', 'side' => 'left']],
]" :config="['showProgress' => false]" />

Building tours

once() auto-starts a tour the first time a visitor sees it; change the key to show a new version. manual() never auto-starts and waits for a trigger. highlight() shows one element instead of a tour.

Driver::tour('welcome')
    ->once('welcome-v1')
    ->step('#search', 'Search', 'Find any customer.', ['side' => 'bottom', 'align' => 'start'])
    ->step(null, 'All set', 'A step with no element shows a centred popover.')
    ->showProgress(true, '{{current}} of {{total}}')
    ->buttonLabels(next: 'Next', previous: 'Back', done: 'Got it');

Starting a tour

Use a button, an Alpine event, or the StartsTours trait in a Livewire component. The tour must be on the page.

<button data-driver-start="welcome">Take the tour</button>

<button x-data @click="$dispatch('driver-js:start', { tour: 'export-hint' })">What's new?</button>

// Livewire, with use AmjadIqbal\DriverJS\Livewire\StartsTours;
$this->startTour('after-save');

Assets and security

  • Tour text is escaped with Js::from().
  • Driver.js 1.10.2 loads from a pinned jsDelivr URL with Subresource Integrity hashes.
  • The scripts carry Laravel's CSP nonce when you use one.
  • To bundle Driver.js with Vite, set 'cdn' => false in config/driver-js.php and import it in resources/js/app.js.
  • Publish the view with php artisan vendor:publish --tag=driver-js-views to change the markup.

Hire me

Need this built into your app, or something custom?

I wrote Laravel Driver.js. I can wire it into your Laravel app, extend it for your case, or build the feature around it. Tell me what you need and you'll get a plan and a quote, free.

Support

Found a bug or want a feature? Open an issue on GitHub. For help adding it to your own project, use the quote form above.

More Laravel packages

All packages
Laravel Sonner: Sonner toast notifications for Laravel, sent from PHP and shown without React.

Laravel Sonner

Sonner toast notifications for Laravel, sent from PHP and shown without React.

Laravel Ninja Keys: A Cmd+K / Ctrl+K command palette for Laravel, with the actions defined in PHP.

Laravel Ninja Keys

A Cmd+K / Ctrl+K command palette for Laravel, with the actions defined in PHP.

Laravel SweetAlert2: SweetAlert2 popups, toasts and confirm dialogs from Laravel controllers, Livewire and Alpine.

Laravel SweetAlert2

SweetAlert2 popups, toasts and confirm dialogs from Laravel controllers, Livewire and Alpine.

Laravel Grid.js: Turn any Eloquent query into a searchable, sortable, paginated Grid.js data table with one fluent PHP call.

Laravel Grid.js

Turn any Eloquent query into a searchable, sortable, paginated Grid.js data table with one fluent PHP call.

Laralink: Work on a Composer package inside the Laravel app that uses it, then switch back to the Packagist release.

Laralink

Work on a Composer package inside the Laravel app that uses it, then switch back to the Packagist release.

Refresher: A drop-in replacement for Laravel's RefreshDatabase that restores a cached snapshot of your test database instead of running migrate:fresh.

Refresher

A drop-in replacement for Laravel's RefreshDatabase that restores a cached snapshot of your test database instead of running migrate:fresh.

Kiln: Artisan commands and an optional signed HTTP route to clear, warm and inspect OPcache when you deploy.

Kiln

Artisan commands and an optional signed HTTP route to clear, warm and inspect OPcache when you deploy.

Laravel Media Viewer: Show private PDFs, video and audio from any Laravel disk without making the files public.

Laravel Media Viewer

Show private PDFs, video and audio from any Laravel disk without making the files public.

Laravel Swiper: Swiper sliders, carousels and image galleries for Laravel as Blade components.

Laravel Swiper

Swiper sliders, carousels and image galleries for Laravel as Blade components.

Laravel MySQL Advisor: Read-only health checks for the MySQL or MariaDB database behind your Laravel app, with the SQL and the Laravel migration to fix a problem wherever a fix applies.

Laravel MySQL Advisor

Read-only health checks for the MySQL or MariaDB database behind your Laravel app, with the SQL and the Laravel migration to fix a problem wherever a fix applies.

Laravel Webhook Console: A dashboard and replay tool for the webhooks spatie/laravel-webhook-client stores in your Laravel app.

Laravel Webhook Console

A dashboard and replay tool for the webhooks spatie/laravel-webhook-client stores in your Laravel app.

Laravel Pennant Dashboard: A browser dashboard for laravel/pennant feature flags: per-scope toggles, sticky percentage rollouts, purge and an audit log.

Laravel Pennant Dashboard

A browser dashboard for laravel/pennant feature flags: per-scope toggles, sticky percentage rollouts, purge and an audit log.

Laravel Notification Inbox: Catches every non-mail Laravel notification in local and staging instead of sending it, and shows each one as it would look on the other end.

Laravel Notification Inbox

Catches every non-mail Laravel notification in local and staging instead of sending it, and shows each one as it would look on the other end.

Laravel WebPush Kit: The browser side of Laravel web push: a subscribe button with a two-step permission prompt, a service worker, and routes that save each user's subscription. Tested in Chrome so far.

Laravel WebPush Kit

The browser side of Laravel web push: a subscribe button with a two-step permission prompt, a service worker, and routes that save each user's subscription. Tested in Chrome so far.

Laravel Redis Advisor: Read-only health checks for the Redis or Valkey behind your Laravel cache, queues, sessions and Horizon, with the redis.conf line or Laravel config that fixes each problem.

Laravel Redis Advisor

Read-only health checks for the Redis or Valkey behind your Laravel cache, queues, sessions and Horizon, with the redis.conf line or Laravel config that fixes each problem.

Need something built?

Free quote in 60 seconds