Fluxo UIFluxo UIv0.4.1

Step Tour

Guided, step-by-step product tours that highlight DOM elements with tooltips. Ideal for onboarding new users or showcasing features after a release.

Basic Tour

A realistic dashboard mock-up with five tour steps covering the header, stats panel, action bar, sidebar navigation, and profile menu.

Interactive dashboard tour

Click 'Start Tour' to walk through each highlighted element.

My Dashboard
JD
John Doe
Users
14,209
+8%
Revenue
$98.4k
+12%
Orders
3,741
+5%
import { StepTour } from 'fluxo-ui';
import type { TourStep } from 'fluxo-ui/types';

const steps: TourStep[] = [
  {
    selector: '#dashboard-header',
    title: 'Dashboard Overview',
    content: 'This is your main dashboard with key metrics.',
    placement: 'bottom',
    order: 1,
  },
  {
    selector: '#sidebar-nav',
    title: 'Navigation',
    content: 'Jump to any section from this sidebar.',
    placement: 'right',
    order: 2,
  },
];

const [isOpen, setIsOpen] = useState(false);

<Button onClick={() => setIsOpen(true)}>Start Tour</Button>

{isOpen && (
  <StepTour
    steps={steps}
    isOpen={isOpen}
    onClose={() => setIsOpen(false)}
  />
)}

Rich JSX Content

Step content supports full JSX, allowing lists, callout boxes, badges, and any custom markup.

Steps with rich JSX content

Tour steps can contain lists, callouts, icons, and styled elements.

๐Ÿ“ค
Export
Multi-format export
โš™๏ธ
Configure
Auto-saved settings
โœ…
Status
All systems go
const steps: TourStep[] = [
  {
    selector: '#export-button',
    title: '๐Ÿš€ New Feature',
    content: (
      <div className="space-y-2 text-sm">
        <p>This powerful feature lets you:</p>
        <ul className="list-disc list-inside space-y-1 text-gray-500">
          <li>Export data in multiple formats</li>
          <li>Schedule automated reports</li>
        </ul>
      </div>
    ),
    placement: 'bottom',
  },
  {
    selector: '#config-panel',
    title: 'โš™๏ธ Configuration',
    content: (
      <div className="space-y-2 text-sm">
        <p>Configure this panel to match your workflow.</p>
        <div className="p-2 rounded bg-yellow-50 text-yellow-800 text-xs">
          Tip: Changes are saved automatically.
        </div>
      </div>
    ),
    placement: 'right',
  },
];

Step Callbacks

Every step exposes onNext, onPrev, and onSkip callbacks. Use them to sync external state, fire analytics events, or trigger side effects at each transition.

Per-step lifecycle callbacks

Start the tour and navigate between steps โ€” live events appear in the log below.

Step 1Step 2Step 3
No events yet. Start the tour to see callbacks fire.
const steps: TourStep[] = [
  {
    selector: '#feature-a',
    title: 'Feature A',
    content: 'This is Feature A.',
    onNext: () => analytics.track('tour_step_next', { step: 1 }),
    onSkip: () => analytics.track('tour_skip', { step: 1 }),
  },
  {
    selector: '#feature-b',
    title: 'Feature B',
    content: 'This is Feature B.',
    onPrev: () => analytics.track('tour_step_prev', { step: 2 }),
    onNext: () => analytics.track('tour_step_next', { step: 2 }),
  },
];

Placement Options

Each step declares a preferred placement. The tooltip automatically falls back to an alternative side when viewport space is insufficient.

Tooltip placements โ€” top ยท bottom ยท left ยท right

Tour through the four placement variants. Watch the tooltip anchor to each side.

Top
Left
๐ŸŽฏ
Right
Bottom
const steps: TourStep[] = [
  { selector: '#el-top',    title: 'Top',    content: '...', placement: 'top'    },
  { selector: '#el-bottom', title: 'Bottom', content: '...', placement: 'bottom' },
  { selector: '#el-left',   title: 'Left',   content: '...', placement: 'left'   },
  { selector: '#el-right',  title: 'Right',  content: '...', placement: 'right'  },
];

// The tooltip falls back gracefully when the viewport has insufficient space.

Start at a Specific Step

Pass initialStep to resume a tour mid-way โ€” useful for restoring progress from local storage or deep-linking into a feature.

Resuming from an arbitrary step

Choose a starting step index (0-based) then launch the tour.

My Dashboard
JD
John Doe
Overview
Reports
Analytics
Settings
Users
14,209
+8%
Revenue
$98.4k
+12%
Orders
3,741
+5%
Starting from: Quick Actions(index 2)
const steps: TourStep[] = [
  { selector: '#header',    title: 'Dashboard Overview', content: '...', placement: 'bottom' },
  { selector: '#stats',     title: 'Key Metrics',        content: '...', placement: 'bottom' },
  { selector: '#actions',   title: 'Quick Actions',      content: '...', placement: 'top'    },
  { selector: '#sidebar',   title: 'Navigation',         content: '...', placement: 'right'  },
  { selector: '#profile',   title: 'Your Profile',       content: '...', placement: 'left'   },
];

// Restore progress from storage
const savedStep = parseInt(localStorage.getItem('tour-step') ?? '0', 10);

{isOpen && (
  <StepTour
    steps={steps}
    isOpen={isOpen}
    onClose={() => setIsOpen(false)}
    initialStep={savedStep}
  />
)}

Dark Mode Support

The tour overlay, highlight, and tooltip all respond to the mode-dark class on document.body. No extra props needed โ€” the theme is inherited automatically via Tailwind's dark-variant utilities.

Light mode
Tooltip background
Overlay (80% black)
Highlight border
Dark mode
Tooltip background
Overlay (60% gray)
Highlight border

API Reference

StepTour props

stepsreq
TourStep[]

Ordered list of tour steps. Each step targets a DOM element via a CSS selector.

isOpenreq
boolean

Controls whether the tour is visible.

onClosereq
() => void

Called when the user skips or completes the tour.

initialStep
number"0"

Zero-based index of the step to start from.

zIndex
number"10050"

Base z-index for the tour overlay, highlight, and tooltip layers. Defaults above modals/drawers per popover rules.

ariaLabel
string"'Product tour'"

Accessible name for the tour dialog read by screen readers.

interactiveHighlight
boolean"false"

When true, clicks pass through the highlight overlay so users can interact with the highlighted element during the tour.

onMissingStep
(stepIndex: number, step: TourStep) => void

Called when a step's selector does not match any element so consumers can advance, retry, or surface the issue.

TourStep

selectorreq
string

CSS selector that identifies the target DOM element for this step.

title
ReactNode

Optional heading shown at the top of the tooltip.

contentreq
ReactNode

Body content of the step tooltip. Supports JSX.

placement
'top' | 'bottom' | 'left' | 'right'"'bottom'"

Preferred side for the tooltip relative to the target element. Falls back automatically if there is not enough space.

order
number

Explicit sort order for this step (defaults to array index position).

onNext
() => void

Callback fired when the user advances past this step.

onPrev
() => void

Callback fired when the user goes back to this step.

onSkip
() => void

Callback fired when the user skips the tour from this step.

Features

DOM Element Targeting

Each step targets any DOM element via a CSS selector, overlaying a highlight with a tooltip.

Rich JSX Content

Step content accepts any React node โ€” lists, callouts, badges, icons, and custom markup.

Four Placements

Tooltip placement can be top, bottom, left, or right with automatic fallback when space is limited.

Step Callbacks

onNext, onPrev, and onSkip callbacks on each step enable analytics, state sync, and side effects.

Resume from Any Step

The initialStep prop lets you deep-link into a specific step or restore saved tour progress.

Overlay & Highlight

A semi-transparent overlay dims the rest of the page while the target element is highlighted with a border.

Dark Mode

Overlay, highlight, and tooltip all adapt automatically to dark/light mode via CSS class inheritance.

Accessibility

Keyboard navigation and focus management ensure the tour is fully accessible for all users.