Tour
A guided sequence of Spotlights: point at one thing, say something, and move to the next with Back / Next / Skip and a progress readout.
Live demo
Tour is a Spotlight with more than one step. It owns the sequence — which step is showing, the Back / Next / Skip / Done buttons, and the progress readout — and drives a single composed <xtyle-spotlight> through it, so every step gets the same honest isolation: the page dims, a hole is cut over the target, and a callout points at it, with the target left live underneath.
Each step is an <xtyle-tour-step> carrying a target and, as its content, whatever the callout should say; any spotlight knob (heading, placement, shape, pulse, arrow, dim, blur, no-dismiss) set on a step overrides the Tour's default for that step alone. The Tour resolves each step's target against the page and hands the element to the spotlight directly, so a selector still finds a node the tour's own shadow root can't see, and the step-to-step focus handling — the part that goes wrong when a sequence is hand-rolled — is the spotlight's, already proven. The only chrome the Tour invents is the nav row; it renders through component.tour, so a mod can reshape Back / Next / Skip and the progress dots without touching the sequencing.
When to use
How this component composes with the rest of the set.
Props
12 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
States
running
A step is showing: the spotlight is open on the step's target and the nav is live.
Anatomy
The named parts that make up the component, with their selectors.
tour
The controller. It paints nothing itself; it drives the composed spotlight and hosts the nav.
spotlight
The composed <xtyle-spotlight> the tour re-points at each step — the veil, the ring, and the callout are all its.
nav
The step controls in the callout's action row: Back, the progress readout, Skip, and Next / Done.
back
Steps back a step. Hidden on the first step.
progress
Which step you're on: 2 of 5 under count, a dot per step under dots, nothing under none.
skip
Ends the tour early. Hidden on the last step, where Done says the same thing.
next
Advances a step, and becomes Done on the last one.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent
--accent-fg
--border-thin
--duration-fast
--ease-standard
--fg-1
--fg-2
--line-2
--radius-full
--radius-sm
--ring
--space-1
--space-2
--space-3
--state-hover
--state-press
--text-xs
--weight-semibold
Slots
The steps, as <xtyle-tour-step> children. Each carries a target and holds the callout content for that step.
Accessibility
Code
A three-step onboarding tour
Point at the compose button, the inbox, and settings in turn, with a dot per step.
<xtyle-tour id="onboard" progress="dots">
<xtyle-tour-step target="#compose" heading="Start here" placement="bottom">
This is where a new message begins.
</xtyle-tour-step>
<xtyle-tour-step target="#inbox" heading="Everything lands here" placement="right">
Your inbox. Unread threads rise to the top.
</xtyle-tour-step>
<xtyle-tour-step target="#settings" heading="Make it yours" placement="left" shape="circle">
Theme, shortcuts, and accounts live in settings.
</xtyle-tour-step>
</xtyle-tour>
<script>
document.getElementById("onboard").start();
</script>
<script lang="ts">
import { Tour, TourStep, Button } from "@xtyle/svelte";
let touring = $state(false);
</script>
<Button onclick={() => (touring = true)}>Take the tour</Button>
<Tour bind:open={touring} progress="count" oncomplete={() => (touring = false)}>
<TourStep target="#compose" heading="Start here">Where a new message begins.</TourStep>
<TourStep target="#inbox" heading="Everything lands here" placement="right">Your inbox.</TourStep>
<TourStep target="#settings" heading="Make it yours" placement="left">Theme and accounts.</TourStep>
</Tour>
---
import { Tour, TourStep } from "@xtyle/astro";
---
<Tour id="onboard" progress="dots">
<TourStep target="#compose" heading="Start here">Where a new message begins.</TourStep>
<TourStep target="#inbox" heading="Everything lands here" placement="right">Your inbox.</TourStep>
<TourStep target="#settings" heading="Make it yours" placement="left" shape="circle">Settings.</TourStep>
</Tour>
<script>
const tour = document.getElementById("onboard") as HTMLElement & { start(): void };
if (!localStorage.getItem("toured")) tour.start();
tour.addEventListener("close", () => localStorage.setItem("toured", "1"));
</script>