Kanzo UI
Overlays & feedback

Tour

A guided walkthrough that spotlights elements on the page, step by step.

Ark UI

Usage

import {
  Tour,
  TourActions,
  TourContent,
  TourDescription,
  TourHeader,
  TourProgressText,
  TourTitle,
  TourTrigger,
  type TourStepType,
} from "@kanzo-tech/ui";
const steps: TourStepType[] = [
  {
    id: "intro",
    type: "dialog",
    title: "Welcome to the board",
    description: "A quick tour.",
    actions: [{ label: "Start", action: "next" }],
  },
  {
    id: "search",
    type: "tooltip",
    target: () => document.getElementById("tour-search"),
    title: "Find the contract",
    description: "Titles, regions and beasts all match here.",
    actions: [
      { label: "Back", action: "prev" },
      { label: "Next", action: "next" },
    ],
  },
];

The content is written once and driven by the step data — TourTitle, TourDescription and TourProgressText read from the active step themselves, so there is nothing to map over.

target is a function rather than a ref because it is called when the step is shown, not when the tour is defined: the element may not have mounted yet, or may be inside a panel the previous step just opened.

Anatomy

Four parts sit under TourContent and are exported for rearranging it. TourPositioner places the step against its target; TourOverlay is the scrim, and is DialogOverlay under the tour's own data-slot; TourSpotlight is the hole punched through that scrim around the target; TourActionTrigger is the raw button behind TourNextStep, TourPreviousStep and TourClose, for a step whose footer needs an action those three do not name.

Tour                         (owns the tour machine)
├── TourTrigger              (starts it)
└── TourContent              (portal + overlay + positioner + spotlight)
    ├── TourHeader
    │   ├── TourTitle
    │   └── TourDescription
    ├── DialogBody           (a step body is Dialog's, not a tour part)
    ├── TourProgressText
    ├── TourActions          (renders the step's `actions` array)
    │   ├── TourPreviousStep
    │   └── TourNextStep
    └── TourClose

TourActions renders whatever the current step declares, mapping prev/dismiss to outline buttons and next to a filled one. Use TourPreviousStep and TourNextStep directly, inside your own DialogFooter, when a step needs its navigation laid out among other footer content — TourActions already carries Ark's Tour.Control, which is a plain div of anatomy attributes, so there is nothing a second tour-shaped footer part would wire up.

Step types

typeBehaviour
dialogCentred modal card with a backdrop. No target.
tooltipAnchored to target, which the spotlight cuts out of the backdrop.
floatingPositioned on the page, unanchored.
waitAdvances on an effect rather than a click.

API Reference

Tour

PropTypeDefault
stepsTourStepType[][]
keyboardNavigationboolean
onStepChange(details: { stepId: string | null }) => void
onStatusChange(details: { status: string }) => void
lazyMountbooleantrue
unmountOnExitbooleantrue

Tour creates the tour machine internally, so unlike Ark's root it takes steps instead of a tour instance. useTourContext() exposes that instance and handleStart to descendants.

useTourContext()

const { tour, handleStart } = useTourContext();

Returns UseTourContextReturntour, Ark's machine api, and handleStart. Both are exported, so a helper that takes what the hook returns can name it.

@ark-ui/react exports a useTourContext of its own, and it is a different hook. Ours is the one bound to Tour, and it returns { tour, handleStart } rather than Ark's tour context. The name matches the reference exactly, which is why it stays — but with both packages in scope the import is worth reading twice: there is no error to tell them apart.

TourStepType

FieldTypeNotes
idstringRequired, unique.
type"dialog" | "tooltip" | "floating" | "wait"See above.
target() => HTMLElement | nullResolved when the step is shown.
title / descriptionReactNodeRendered by TourTitle / TourDescription.
actions{ label: string; action?: "next" | "prev" | "dismiss" | "skip" }[]Footer buttons.
placementPlacement | "center"Relative to target.
backdropbooleanDim the page behind this step.

TourContent

PropTypeDefault
showCloseButtonbooleantrue

Like Dialog, TourTitle reserves inline-end padding whenever the close trigger is present, so a long step title wraps instead of running under the X.

On this page