Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Components

Free

Tour for React Aria

Walk a first visit through the page, one highlighted control after another. For React with React Aria, when people should be shown the next control.

Framework
UI library

React Aria does not include this primitive, so this page uses the Ark UI component. The visuals match the Ark UI version.

Steps that point at one control at a time. A step that never points at a control is just a dialog.

Use it when a first visit should show the next control. For one hint with no sequence, use a Tooltip. In React, React Aria follows the steps you pass.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Tour anatomy: spotlight, title, close, description, progress text, action trigger, content
TourContent
TourActionTrigger
TourClose
TourProgressText
TourTitle
TourDescription
TourPositioner
TourArrow
└── TourArrowTip
TourOverlay
TourSpotlight

Usage

import React from "react";
import { Button } from "@/components/ui/button";
import {
  Tour, TourContent, TourDescription, TourFooter, TourHeader,
  TourNextStep, TourPreviousStep, TourProgressText, type TourStepType,
  TourTitle, TourTrigger,
} from "@/components/ui/tour";
const TourDemo = () => {
  const installRef = React.useRef<HTMLButtonElement>(null);
  const usageRef = React.useRef<HTMLDivElement>(null);

  const steps = React.useMemo<TourStepType[]>(
    () => [
      {
        actions: [{ action: "next", label: "Start tour" }],
        description:
          "This walkthrough stays inside the preview. Next steps highlight pieces of this mini app.",
        id: "welcome",
        title: "Welcome",
        type: "dialog",
      },
      {
        actions: [
          { action: "prev", label: "Back" },
          { action: "next", label: "Next" },
        ],
        description: "Use the CLI or a manual install from this control.",
        id: "install",
        placement: "bottom",
        target: () => installRef.current,
        title: "Install",
        type: "tooltip",
      },
      {
        actions: [
          { action: "prev", label: "Back" },
          { action: "next", label: "Next" },
        ],
        description:
          "Usage notes live next to install so you can copy a snippet.",
        id: "usage",
        placement: "top",
        target: () => usageRef.current,
        title: "Usage",
        type: "tooltip",
      },
      {
        actions: [{ action: "dismiss", label: "Done" }],
        description:
          "The overlay, spotlight, and popover are clipped to this frame.",
        id: "done",
        title: "That’s it",
        type: "dialog",
      },
    ],
    []
  );

  return (
    <Tour steps={steps}>
      <div className="flex w-full max-w-lg flex-col overflow-hidden rounded-xl border bg-background shadow-sm">
        <header className="flex items-center justify-between gap-3 border-b px-3 py-2.5">
          <span className="font-semibold text-sm">Acme UI</span>
          <div className="flex items-center gap-1">
            <Button ref={installRef} size="sm" type="button" variant="ghost">
              Install
            </Button>
            <TourTrigger asChild>
              <Button size="sm">Start tour</Button>
            </TourTrigger>
          </div>
        </header>

        <div className="grid gap-3 p-4 sm:grid-cols-2">
          <div className="rounded-lg border bg-muted/40 p-3">
            <p className="font-medium text-sm">Install</p>
            <p className="mt-1 text-muted-foreground text-xs">
              Add the component with the CLI, then import it.
            </p>
          </div>
          <div className="rounded-lg border bg-muted/40 p-3" ref={usageRef}>
            <p className="font-medium text-sm">Usage</p>
            <p className="mt-1 text-muted-foreground text-xs">
              Compose steps, then call start() from a trigger.
            </p>
          </div>
        </div>
      </div>

      <TourContent>
        <TourHeader>
          <TourProgressText />
          <TourTitle />
          <TourDescription />
        </TourHeader>
        <TourFooter>
          <TourPreviousStep />
          <TourNextStep />
        </TourFooter>
      </TourContent>
    </Tour>
  );
};

Accessibility

Arrow Right
Moves to the next step in the tour.
Arrow Left
Moves to the previous step in the tour.
Escape
Closes the tour.
Enter
Activate the focused control.
Space
Activate the focused control.

Demos

Async

The second step fetches a GitHub profile before it will appear. Until the response arrives the step stays hidden, still titled as loading. effect then updates the title and description with the name, the public repo count, and the follower count, and calls show. A failed request fills the step with an error instead of leaving it blank, and leaving the step aborts the fetch.

Preview width

Custom Spacing

The step panel uses a tighter --space than the default, set on TourContent through the spacing scale. Header and footer padding both follow that variable, so one token restyles the panel. Use a smaller value when the tour is cramped inside a preview. The same variable can grow at a wider breakpoint without new styles on each part.

Preview width

Events

A log under the targets records onStepChange with the step id and onStatusChange with the tour status, appending a line as you move forward, back, and finish. Use the callbacks when you need to remember that someone finished the walkthrough, or to keep another part of the page in sync with the current step. The log is your markup. The tour does not render one.

Preview width

Keyboard Navigation

keyboardNavigation is turned on, and the line under the button says how: the right arrow advances, the left arrow goes back, and Escape closes. The steps are tooltips on three targets. Turn this on when people should move through the tour without aiming at Next. Leave it off when those arrow keys already do something else on the page.

Preview width

Progress

Four tooltip steps, plus a bar along the bottom of the panel whose width is the tour progress percent. TourProgressText still prints the count above the title. Read the percent from the tour context when you want a graphic rather than only that count. The bar is your own element, pinned to the bottom of the content, and it does not ship with the component.

Preview width

Skip

The early steps offer Skip beside Next. Skip is an action whose action is dismiss, so it closes the tour immediately. The last step says Finish and dismisses the same way. Add a skip when the walkthrough is optional, and keep Back on the later steps so closing is not the only way out.

Preview width

Step Types

The opening and closing steps use type dialog: centered, with no target. Between them, a tooltip step anchors to the target element, and a floating step sits at placement bottom-end with no element at all. Use dialog for a welcome or a goodbye, tooltip when you are pointing at a control, and floating when the note should hold a corner while the page stays visible.

Preview width

Wait For Click

Add, then Edit, then Delete, and none of those steps has a Next button. effect shows the step, waits for a click on that target, and only then moves on. Use this when the lesson is the click itself, not a paragraph about the click. The closing dialog is the first step that offers Finish, after all three buttons have been used.

Preview width

Wait For Element

Clicking Add Item appends a row, and the next step stays hidden until that row exists. The wait looks for an element marked data-item new, and it gives up after five seconds. Use this when the next target is created by the previous action, such as a row or a panel that was not in the page yet. Pointing earlier would highlight nothing.

Preview width

Wait For Input

The name step moves on only after the field has at least two characters. The email step waits for an address shape, and the terms step waits until the checkbox is checked. Each one listens for input or change and tests the element before advancing. Use this when continuing on an empty or invalid value would skip the lesson.

Preview width

FAQ

How do I build a product tour or onboarding walkthrough in React?

Describe the tour as an array of steps, each with an id, a title, a description, a type and its actions, pass it to Tour, and start it with a TourTrigger, as the default demo does. Steps of type tooltip point at an element with target.

How do I highlight a specific element in a Tour step?

Give the step a target, a function that returns the element, and a placement such as bottom. The Tour scrolls it into view, spotlights it with an overlay and places the step next to it.

What step types does the Tour support?

Three, shown in the Step Types demo: dialog for a centered step with no target, like a welcome screen; tooltip for a step attached to an element; and floating for a step pinned to a corner of the screen.

How do I wait for the user to click a button before the next Tour step?

Use the step's effect: it receives next, target and show, so it can wait for an event and then call next. Ark's waitForEvent helper does the waiting, as the Wait For Click and Wait For Input demos do, and waitForElement waits for an element to appear, as the Wait For Element demo does.

How do I load data before showing a Tour step?

Do the work in the step's effect and call show once it is done, or update to change the step's content, as the Async demo does. The step stays hidden while it loads.

How do I let users skip or close the Tour?

Add an action with action set to dismiss, labeled Skip or Done, as the Skip demo does. Escape and a click outside also close it, unless you turn off closeOnEscape or closeOnInteractOutside.

How do I know when a Tour step changes or the Tour ends?

Pass onStepChange to follow the current step, and onStatusChange to know when the Tour starts, completes or is dismissed, as the Events demo does. Use the status to remember that a user has finished it.

How do I install the Tour in React?

Run the command in the Installation section above: it adds the Tour to your ui folder. It is built on Ark UI on every base and framework. The command uses the shadcn CLI.

API Reference

Tour

<div> data-slot="tour"

PropType
stepsTourStepDetails[]

The steps to display in the tour.

Default
[]
dir?"ltr" | "rtl"

The document's text/writing direction.

Type
"ltr" | "rtl"
Default
"ltr"
id?string

The unique identifier of the machine.

ids?object

The ids of the scroll area elements.

Type
{ root?: string; viewport?: string; content?: string; scrollbar?: string; thumb?: string }
keyboardNavigation?boolean

Enable arrow key navigation between steps.

onStatusChange?(details: { status: string }) → void

Called when the tour status changes.

Type
(details: { status: string }) → void
Parameters

details – { status: string }

Returns
void
onStepChange?(details: { stepId: string | null }) → void

Called when the current step changes.

Type
(details: { stepId: string | null }) → void
Parameters

details – { stepId: string | null }

Returns
void
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

AttributeType
data-overflow-x?string

Present when the content overflows the x-axis.

data-overflow-y?string

Present when the content overflows the y-axis.

CSS variableType
--corner-heightstring

The height of the Root.

--corner-widthstring

The width of the Root.

--thumb-heightstring

The height of the slider thumb.

--thumb-widthstring

The width of the slider thumb.

TourContent

<div> data-slot="tour-content"

PropType
showCloseButton?boolean

Show close button at the top right corner.

Default
true
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

AttributeType
data-overflow-x?string

Present when the content overflows the x-axis.

data-overflow-y?string

Present when the content overflows the y-axis.

TourTrigger

<button> data-slot="tour-trigger"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

AttributeType
data-overflow-x?string

Present when scrollbarXHidden is false.

data-overflow-y?string

Present when scrollbarYHidden is false.

TourActionTrigger

data-slot="tour-action-trigger"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

TourOverlay

data-slot="tour-overlay"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourPositioner

data-slot="tour-positioner"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourBody

data-slot="tour-body"

AttributeType
data-overflow-x?string

Present when scrollbarXHidden is false.

data-overflow-y?string

Present when scrollbarYHidden is false.

TourSpotlight

data-slot="tour-spotlight"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourHeader

data-slot="tour-header"

AttributeType
data-overflow-x?string

Present when scrollbarXHidden is false.

data-overflow-y?string

Present when scrollbarYHidden is false.

TourTitle

data-slot="tour-title"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourDescription

data-slot="tour-description"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourProgressText

data-slot="tour-progress-text"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourClose

data-slot="tour-close-trigger"

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

TourFooter

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

TourActions

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

className?string

Merged with the part's classes.

TourPreviousStep

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

AttributeType
data-overflow-x?string

Present when scrollbarXHidden is false.

data-overflow-y?string

Present when scrollbarYHidden is false.

TourNextStep

PropType
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.

AttributeType
data-overflow-x?string

Present when scrollbarXHidden is false.

data-overflow-y?string

Present when scrollbarYHidden is false.

With other components

  • Button

    Buttons

    Next, back, and done

  • Dialog

    Overlays

    A step in the center

  • Popover

    Overlays

    A step on a control

  • Card

    Layout

    The step body

  • Badge

    Feedback

    Step two of five

  • Progress

    Feedback

    How far the tour is

  • Tooltip

    Overlays

    One hint, not a sequence

  • Hint

    Feedback

    A note that stays

  • Steps

    Navigation

    The sequence in the page

  • Sheet

    Overlays

    A panel of help

  • Announcement

    Feedback

    One message for everyone

  • Empty

    Feedback

    A first-run placeholder