Skip to content

Tour

Guided tour with spotlight highlighting and step navigation.

import { Tour } from 'asterui'

Basic Tour

A simple guided tour with multiple steps.

import { Tour, Button, Input, Card } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const searchRef = useRef<HTMLInputElement>(null);
  const profileRef = useRef<HTMLButtonElement>(null);
  const settingsRef = useRef<HTMLButtonElement>(null);
  
  const steps = [
    {
      target: searchRef,
      title: 'Search',
      description: 'Use the search bar to find content quickly.',
      placement: 'bottom' as const,
    },
    {
      target: profileRef,
      title: 'Profile',
      description: 'Click here to view and edit your profile.',
      placement: 'bottom' as const,
    },
    {
      target: settingsRef,
      title: 'Settings',
      description: 'Customize your experience in settings.',
      placement: 'left' as const,
    },
  ];
  
  return (
      <Card className="p-4">
        <div className="flex gap-4 items-center mb-4">
          <Input ref={searchRef} placeholder="Search..." className="flex-1" />
          <Button ref={profileRef}>Profile</Button>
          <Button ref={settingsRef}>Settings</Button>
        </div>
        <Button color="primary" onClick={() => setOpen(true)}>
          Start Tour
        </Button>
        <Tour
          open={open}
          steps={steps}
          onClose={() => setOpen(false)}
          onFinish={() => setOpen(false)}
        />
      </Card>
    )
}

export default App

Tour Without Target

Steps without a target appear centered on screen.

import { Tour, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const steps = [
    {
      title: 'Welcome!',
      description: 'This tour will guide you through the main features.',
    },
    {
      title: 'Getting Started',
      description: 'Follow along to learn how to use this application.',
    },
    {
      title: 'All Done!',
      description: 'You are ready to start using the app.',
    },
  ];
  
  return (
      <Button color="primary" onClick={() => setOpen(true)}>
        Start Intro
      </Button>
      <Tour
        open={open}
        steps={steps}
        onClose={() => setOpen(false)}
        type="primary"
      />
    )
}

export default App

With Cover Image

Add images or custom content above the step title.

import { Tour, Button } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  
  const steps = [
    {
      target: buttonRef,
      title: 'New Feature',
      description: 'Check out this amazing new feature we just added!',
      cover: (
        <img
          src="https://picsum.photos/320/160"
          alt="Feature preview"
          className="w-full h-40 object-cover"
        />
      ),
      placement: 'right' as const,
    },
  ];
  
  return (
      <Button ref={buttonRef} color="primary" onClick={() => setOpen(true)}>
        View Feature
      </Button>
      <Tour
        open={open}
        steps={steps}
        onClose={() => setOpen(false)}
        showSkip={false}
      />
    )
}

export default App

Placements

Control where the popover appears relative to the target.

Target
import { Tour, Button, Space } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const targetRef = useRef<HTMLDivElement>(null);
  const placements = ['top', 'right', 'bottom', 'left'] as const;
  const [placementIndex, setPlacementIndex] = useState(0);
  
  const steps = [
    {
      target: targetRef,
      title: `Placement: ${placements[placementIndex]}`,
      description: 'The popover can appear on any side of the target.',
      placement: placements[placementIndex],
    },
  ];
  
  return (
      <div className="flex flex-col items-center gap-4">
        <div
          ref={targetRef}
          className="w-24 h-24 bg-primary text-primary-content flex items-center justify-center rounded-lg"
        >
          Target
        </div>
        <Space>
          <Button onClick={() => setPlacementIndex((i) => (i + 1) % 4)}>
            Change Placement
          </Button>
          <Button color="primary" onClick={() => setOpen(true)}>
            Show Tour
          </Button>
        </Space>
        <Tour
          open={open}
          steps={steps}
          onClose={() => setOpen(false)}
          showIndicators={false}
        />
      </div>
    )
}

export default App
PropertyDescriptionTypeDefault
openWhether tour is visiblebooleanfalse
stepsTour steps configurationTourStepProps[]-
currentCurrent step index (controlled)number-
onChangeCallback when step changes(current: number) => void-
onCloseCallback when tour closes() => void-
onFinishCallback when tour finishes() => void-
maskShow mask overlay with spotlightbooleantrue
typeButton style type'default' | 'primary''default'
gapGap between spotlight and target [radius, offset] or numbernumber | [number, number]8
showSkipShow skip buttonbooleantrue
showIndicatorsShow step indicatorsbooleantrue
closeOnMaskClickClose on mask clickbooleantrue
closeOnEscapeClose on Escape keybooleantrue
scrollIntoViewScroll target into viewbooleantrue
prevButtonTextText for previous buttonReact.ReactNode'Previous'
nextButtonTextText for next buttonReact.ReactNode'Next'
finishButtonTextText for finish buttonReact.ReactNode'Finish'
skipButtonTextText for skip buttonReact.ReactNode'Skip'
zIndexZ-index for tour overlaynumber1000
PropertyDescriptionTypeDefault
targetTarget element ref or function returning elementRefObject<HTMLElement> | (() => HTMLElement | null) | null-
titleStep titleReact.ReactNode-
descriptionStep descriptionReact.ReactNode-
coverCover image or content above titleReact.ReactNode-
placementPopover placement relative to targetTourPlacement'bottom'
classNameCustom class for step popoverstring-
onOpenCalled when step becomes active() => void-
onCloseCalled when leaving step() => void-
  • Tour dialog has role=“dialog” and aria-modal=“true”
  • Arrow keys navigate between steps
  • Escape key closes the tour
  • Step indicators are keyboard accessible
  • Focus is trapped within the tour when open