Phoundry UI

Tour Experimental

A multi-step guided tour overlay that highlights target elements and displays positioned popover cards with navigation controls.

import { Tour } from 'phoundry-ui';
import type { TourStepDef } from 'phoundry-ui';

Basic Tour

Show code
let open = $state(false);
let ref1, ref2, ref3;

const steps: TourStepDef[] = [
  { target: () => ref1, title: 'Upload', description: 'Upload a file.' },
  { target: () => ref2, title: 'Save', description: 'Save changes.' },
  { target: () => ref3, title: 'More', description: 'Extra options.' },
];

<Button bind:element={ref1}>Upload</Button>
<Button bind:element={ref2}>Save</Button>
<Button bind:element={ref3}>More</Button>
<Button onclick={() => open = true}>Begin Tour</Button>
<Tour bind:open {steps} />

Placement

Show code
<Tour steps={[{ target: () => el, placement: 'top' }]} />

Non-modal (mask=false)

Show code
<Tour bind:open mask={false} type="primary" steps={steps} />

Custom Gap

Show code
<Tour gap={{ offset: 12, radius: 8 }} steps={steps} />

Controlled State

Step: 0
Show code
let open = $state(false);
let step = $state(0);

<Tour bind:open bind:current={step} steps={steps} />
<Button onclick={() => { step = 1; open = true; }}>Jump to Step 2</Button>

Tour Props

PropTypeDefaultDescription
steps requiredTourStepDef[]Array of step definitions.
open booleanfalseWhether the tour is visible. Bindable.
current number0Active step index. Bindable.
onClose () => voidCalled when the tour is dismissed.
onChange (current: number) => voidCalled when the step changes.
mask booleantrueShow dimmed mask overlay with target cutout.
type 'default' | 'primary''default'Card color scheme.
gap { offset?: number; radius?: number }{ offset: 6, radius: 4 }Highlight area gap around the target element.
arrow booleantrueShow arrow pointing from card to target.
placement TourPlacement'bottom'Default placement for all steps.
zIndex number350z-index of the tour overlay layer.
scrollIntoViewOptions boolean | ScrollIntoViewOptionstrueScroll targets into view before showing.
disabledInteraction booleanfalseBlock interaction with highlighted element.
indicatorsRender Snippet<[current, total]>Custom step indicator renderer.

TourStepDef

PropTypeDefaultDescription
target () => HTMLElement | nullElement to highlight. Omit for center-screen placement.
title stringStep title.
description stringStep description text.
cover SnippetCover content (image/video) above the title.
placement TourPlacementOverride placement for this step.
mask booleanOverride global mask setting for this step.
scrollIntoView boolean | ScrollIntoViewOptionsOverride scroll behavior for this step.
nextButtonText stringCustom "Next" / "Finish" button label.
prevButtonText stringCustom "Previous" button label.

Usage tips

  • Use bind:open and bind:current to control the tour externally.
  • Each step’s target is a function returning an HTMLElement — use bind:element on buttons or document.getElementById.
  • Omitting target (or returning null) centers the card on screen — useful for intro/welcome steps.
  • Set mask=false with type="primary" for a non-modal tour that doesn’t block interaction.
  • The gap prop controls the highlight cutout padding (offset) and corner rounding (radius) around the target.
  • Keyboard: Escape closes, ArrowLeft/ArrowRight navigate steps.
  • Set disabledInteraction when you want the highlighted control read-only while still visually emphasizing it.
  • Turn off arrow for dense layouts where the pointer would collide with nearby UI; combine with type="primary" for contrast.
  • Raise zIndex if other overlays (command palette, modal) share the same stacking context and occlude the tour.