Skip to content

Product Tours

Guided, spotlight-style tours for your modules: declare each tour once in the backend, mount one global host in your layout, and the right tour auto-starts — exactly once — for the users allowed to see it. Rendering is powered by driver.js (the most popular, actively-maintained tour engine — ~5 kB, MIT) themed to the shadcn tokens by the published kinetix.css, so popovers, buttons and the overlay follow your template's design line in light and dark.

Looking for the setup checklist or the lightweight dependency-free tour? See Onboarding. This module supersedes the old useKinetixTour composable for anything backend-driven.

1. Setup

bash
# .env
KINETIX_TOURS_ENABLED=true

Install the renderer in the host app (opt-in dependency):

bash
php artisan kinetix:install --tours   # adds driver.js to package.json

Mount the host once in your app layout — it's renderless:

vue
<script setup lang="ts">
import KinetixTours from '@/components/kinetix/KinetixTours.vue';
</script>

<template>
  <slot />
  <KinetixTours />
</template>

2. Declaring tours

One tour per module, from any service provider. Tag the target elements with data-tour attributes in your pages:

php
use Happones\Kinetix\Tours\KinetixTours;
use Happones\Kinetix\Tours\TourStep;

KinetixTours::tour('posts')
    ->page('Kinetix/Posts/Index')          // Inertia component (or ->url('/posts*'))
    ->permission('posts.viewAny')          // optional: Gate-checked server-side
    ->steps([
        TourStep::make('[data-tour=create]')
            ->title(__('tours.posts.create'))
            ->description(__('tours.posts.create_body'))
            ->side('bottom'),
        TourStep::make('[data-tour=filters]')
            ->title(__('tours.posts.filters')),
    ]);
MethodBehaviour
page('Kinetix/Posts/Index')Match by Inertia component name (* wildcards) — preferred, team-prefix-proof
url('/posts*')Match by URL path (* wildcards)
permission('posts.viewAny')Users the Gate denies never receive the tour (filtered server-side)
auto(false)Never auto-start — manual launches only (help menu, replay button)
TourStep::side()/align()driver.js popover positioning (top/right/bottom/left, start/center/end)

Wrap step copy in __() — tours are user-facing strings and follow the same localization rule as every developer-declared label.

3. Seen state: local vs database

kinetix.tours.driver picks where "already seen" is remembered:

DriverStorageSurvivesNeeds
local (default)Browser localStorageThe browser profileNothing
databasekinetix_tour_state per userDevices, browsers, resets by an adminvendor:publish --tag=kinetix-tours-migrations && php artisan migrate

With database, the host persists through the team-aware {prefix}/tours/{id}/seen endpoints (POST = seen, DELETE = re-arm). Both finishing and dismissing a tour count as seen — tours never nag.

4. Manual control (the pinia store)

Anything can start or re-arm a tour through the store — a "Replay tour" item in your help menu, for example:

vue
<script setup lang="ts">
import { useKinetixToursStore } from '@/stores/kinetixTours';

const tours = useKinetixToursStore();
</script>

<template>
  <DropdownItem @click="tours.start('posts')">Replay the posts tour</DropdownItem>
</template>
Store APIBehaviour
start(id)Run a tour now (ignores seen state)
hasSeen(id) / markSeen(id) / reset(id)Inspect / persist through the configured driver
tours / enabled / activeTourIdReactive share state

5. Theming

<KinetixTours /> ships its own popover theme (scoped by popoverClass: 'kinetix-tour-popover', so a host using driver.js for other purposes stays unaffected). Colors resolve through the Tailwind-level --color-popover / --color-border / --color-primary / … variables, which exist in both token conventions (kinetix.css HSL triplets and starter-kit complete colors) — so the popover follows the active theme at that moment: light, dark, or system (html.dark flips and every token shifts with it, mid-tour included). Override the class in your CSS to fine-tune.

6. Config reference

php
'tours' => [
    'enabled' => env('KINETIX_TOURS_ENABLED', false),
    'driver'  => env('KINETIX_TOURS_DRIVER', 'local'), // 'local' | 'database'
],

Released under the MIT License.