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.

A step can point at something taller than the screen — a whole table. The tour then highlights its top, down to what fits with the message, so the page doesn't jump and the message stays beside what it describes. For the sharpest spotlight, still point a step at the part you talk about (the toolbar, the first column) rather than the whole page section.

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.