smithery/neversight

flowsterix-best-practices

Use when user asks to "create a tour", "add onboarding flow", "implement guided walkthrough", "set up Flowsterix", "add tour steps", "configure step targeting", "handle async content in tour", or needs help with tour overlays, popovers, step advance rules, or TourHUD configuration.

Installation

$ npx skills add smithery/neversight --skill flowsterix-best-practices

Summary

Use when user asks to "create a tour", "add onboarding flow", "implement guided walkthrough", "set up Flowsterix", "add tour steps", "configure step targeting", "handle async content in tour", or needs help with tour overlays, popovers, step advance rules, or TourHUD configuration.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/neversight · top by installs.

npx skills add smithery/neversight

Browse all from smithery/neversight

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version0.1.0
More metadata
tags
flowsterix, tour, onboarding, walkthrough, guide, react

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 12,563 B
  • docs SUMMARY.md 315 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Flowsterix Best Practices

Flowsterix is a state machine-based guided tour library for React applications. Flows are declarative step sequences with automatic progression rules, lifecycle hooks, and persistence.

Quick Start

Installation

# Core packages
npm install @flowsterix/core @flowsterix/react motion

# Recommended: Add preconfigured shadcn components
npx shadcn@latest add https://flowsterix.com/r/tour-hud.json

Prefer the shadcn components - they provide polished, accessible UI out of the box and follow the design patterns shown in the examples.

Minimal Example

import { createFlow, type FlowDefinition } from '@flowsterix/core'
import { TourProvider, TourHUD } from '@flowsterix/react'
import type { ReactNode } from 'react'

const onboardingFlow: FlowDefinition<ReactNode> = createFlow({
  id: 'onboarding',
  version: { major: 1, minor: 0 },
  autoStart: true,
  steps: [
    {
      id: 'welcome',
      target: 'screen',
      advance: [{ type: 'manual' }],
      content: <p>Welcome to our app!</p>,
    },
    {
      id: 'feature',
      target: { selector: '[data-tour-target="main-feature"]' },
      advance: [{ type: 'event', event: 'click', on: 'target' }],
      content: <p>Click this button to continue</p>,
    },
  ],
})

export function App({ children }) {
  return (
    <TourProvider flows={[onboardingFlow]} storageNamespace="my-app">
      <TourHUD overlay={{ showRing: true }} />
      {children}
    </TourProvider>
  )
}

Core Concepts

FlowDefinition

createFlow({
  id: string,                          // Unique identifier
  version: { major: number, minor: number },  // For storage migrations
  steps: Step[],                       // Array of tour steps
  autoStart?: boolean,                 // Start on mount (default: false)
  resumeStrategy?: 'chain' | 'current', // How to run onResume hooks
  hud?: FlowHudOptions,                // UI configuration
  migrate?: (ctx) => FlowState | null, // Version migration handler
})

Step Anatomy

{
  id: string,                    // Unique within flow
  target: StepTarget,            // What to highlight
  content: ReactNode,            // Popover content
  advance?: AdvanceRule[],       // When to move to next step
  placement?: StepPlacement,     // Popover position
  route?: string | RegExp,       // Only show on matching routes
  waitFor?: StepWaitFor,         // Block until condition met
  targetBehavior?: StepTargetBehavior,  // Scroll/visibility handling
  onEnter?: (ctx) => void,       // Fires when step activates
  onResume?: (ctx) => void,      // Fires when resuming from storage
  onExit?: (ctx) => void,        // Fires when leaving step
  controls?: { back?, next? },   // Button visibility
}

Step Targets

// Full-screen overlay (no element highlight)
target: 'screen'

// CSS selector (recommended: use data attributes)
target: {
  selector: '[data-tour-target="feature"]'
}

// Dynamic node resolution
target: {
  getNode: () => document.querySelector('.dynamic-el')
}

Always use data-tour-target attributes instead of CSS classes for stability.

Advance Rules

Rules define when a step automatically progresses. First matching rule wins.

Type Usage Example
manual Next button only { type: 'manual' }
event DOM event on target { type: 'event', event: 'click', on: 'target' }
delay Timer-based { type: 'delay', ms: 3000 }
route URL change { type: 'route', to: '/dashboard' }
predicate Polling condition { type: 'predicate', check: (ctx) => isReady() }
// Combine rules for flexibility
advance: [
  { type: 'event', event: 'click', on: 'target' },
  { type: 'delay', ms: 10000 }, // Fallback after 10s
]

React Integration

TourProvider Props

<TourProvider
  flows={[flow1, flow2]} // Flow definitions
  storageNamespace="my-app" // localStorage key prefix
  persistOnChange={true} // Auto-save state changes
  backdropInteraction="block" // 'block' | 'passthrough'
  lockBodyScroll={false} // Prevent page scroll
  analytics={{
    // Event handlers
    onFlowStart: (p) => track('tour_start', p),
    onStepEnter: (p) => track('step_view', p),
  }}
/>

useTour Hook

const {
  activeFlowId, // Currently active flow ID or null
  state, // FlowState: status, stepIndex, version
  activeStep, // Current Step object
  startFlow, // (flowId, options?) => start a flow
  next, // () => advance to next step
  back, // () => go to previous step
  pause, // () => pause the flow
  cancel, // (reason?) => cancel the flow
  complete, // () => mark flow complete
} = useTour()

TourHUD Configuration

<TourHUD
  overlay={{
    padding: 12, // Padding around highlight
    radius: 12, // Border radius of cutout
    showRing: true, // Glow effect around target
    blurAmount: 6, // Backdrop blur (px)
  }}
  popover={{
    maxWidth: 360,
    offset: 16, // Distance from target
  }}
  controls={{
    showSkip: true,
    skipMode: 'hold', // 'click' | 'hold' (hold-to-confirm)
  }}
  progress={{
    show: true,
    variant: 'dots', // 'dots' | 'bar' | 'fraction'
  }}
/>

Common Mistakes

  1. Missing data-tour-target attributes - Tour cannot find elements

```tsx // Bad: fragile to styling changes target: { selector: '.btn-primary' }

// Good: semantic and stable target: { selector: '[data-tour-target="submit-btn"]' } ```

  1. No waitFor for async content - Step shows before content ready

``tsx // Add waitFor when targeting dynamically loaded elements waitFor: { selector: '[data-tour-target="api-result"]', timeout: 8000 } ``

  1. Ignoring sticky headers - Target scrolls behind fixed navigation

``tsx targetBehavior: { scrollMargin: { top: 80 }, // Height of sticky header scrollMode: 'start', } ``

  1. Wrong version format - Use object, not number

```tsx // Bad version: 1

// Good version: { major: 1, minor: 0 } ```

  1. Forgetting onResume hooks - UI state not restored after reload

```tsx // Bad: UI broken after page reload onEnter: () => ensureMenuOpen(),

// Good: Both hooks restore UI state onEnter: () => ensureMenuOpen(), onResume: () => ensureMenuOpen(), onExit: () => ensureMenuClosed(), ```

Shadcn Components

The shadcn registry provides preconfigured, polished components. Always prefer these over custom implementations.

Important: The tour components require shadcn CSS variables (--popover, --border, --destructive, etc.). If you're not using shadcn/ui, see [CSS Setup](references/css-setup.md) for the required variables.

Available Components

Component Install Command Usage
tour-hud npx shadcn@latest add https://flowsterix.com/r/tour-hud.json Full HUD with overlay & popover
step-content npx shadcn@latest add https://flowsterix.com/r/step-content.json Step layout primitives

Step Content Primitives

Use these components for consistent step styling:

import {
  StepContent,
  StepTitle,
  StepText,
  StepHint,
} from '@/components/step-content'

content: (
  <StepContent>
    <StepTitle>Feature Discovery</StepTitle>
    <StepText>
      This is the main explanation text with muted styling.
    </StepText>
    <StepHint>Click the button to continue.</StepHint>
  </StepContent>
)
  • StepContent - Grid container with proper spacing
  • StepTitle - Semibold heading (supports size="lg" for welcome screens)
  • StepText - Muted paragraph text
  • StepHint - Italic hint text for user instructions

Lifecycle Hooks

Lifecycle hooks synchronize UI state with tour progression. Use them when steps target elements inside collapsible panels, modals, drawers, or other dynamic UI.

When to Use Each Hook

Hook Fires When Purpose
onEnter Step activates (fresh start) Open UI, prepare state
onResume Step restores from storage Restore UI after page reload
onExit Leaving step (next/back/skip) Clean up, close UI

Common Patterns

1. Opening/Closing Drawers & Menus

// Helper functions to toggle menu state
const ensureMenuOpen = () => {
  const panel = document.querySelector('[data-tour-target="menu-panel"]')
  if (!(panel instanceof HTMLElement)) return
  const isClosed = panel.classList.contains('-translate-x-full')
  if (isClosed) {
    document.querySelector('[data-tour-target="menu-button"]')?.click()
  }
}

const ensureMenuClosed = () => {
  const panel = document.querySelector('[data-tour-target="menu-panel"]')
  if (!(panel instanceof HTMLElement)) return
  const isClosed = panel.classList.contains('-translate-x-full')
  if (!isClosed) {
    panel.querySelector('[aria-label="Close menu"]')?.click()
  }
}

2. Step Targeting Element Inside Drawer

{
  id: 'menu-link',
  target: { selector: '[data-tour-target="api-link"]' },
  onEnter: () => ensureMenuOpen(),   // Open drawer on fresh entry
  onResume: () => ensureMenuOpen(),  // Open drawer on page reload
  onExit: () => ensureMenuClosed(),  // Close drawer when leaving
  advance: [{ type: 'route', to: '/api-demo' }],
  content: (
    <StepContent>
      <StepTitle>API Demo</StepTitle>
      <StepText>Click to explore the API features.</StepText>
    </StepContent>
  ),
}

3. Expanding Nested Accordions

const ensureAccordionExpanded = () => {
  ensureMenuOpen() // Parent must be open first
  const submenu = document.querySelector('[data-tour-target="submenu"]')
  if (submenu) return // Already expanded
  document.querySelector('[data-tour-target="accordion-toggle"]')?.click()
}

{
  id: 'submenu-item',
  target: { selector: '[data-tour-target="submenu"]' },
  onResume: () => ensureAccordionExpanded(),
  content: ...
}

4. Closing UI When Moving Away

{
  id: 'feature-grid',
  target: { selector: '#feature-grid' },
  onEnter: () => {
    setTimeout(() => ensureMenuClosed(), 0) // Allow menu click to register first
  },
  onResume: () => ensureMenuClosed(),
  content: ...
}

Critical Rules

  1. Always implement onResume when you have onEnter - Users may reload the page mid-tour
  2. Check state before acting - Don't toggle already-open menus
  3. Use setTimeout for sequential actions - Give previous clicks time to register
  4. Keep hooks idempotent - Safe to call multiple times

Step Placements

'auto' | 'top' | 'bottom' | 'left' | 'right' |
'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' |
'left-start' | 'left-end' | 'right-start' | 'right-end' |
'auto-start' | 'auto-end'

Additional Resources

  • [CSS Setup](references/css-setup.md) - Required shadcn CSS variables
  • [Flow Patterns](references/flow-patterns.md) - Targeting, advance rules, waitFor
  • [React Integration](references/react-integration.md) - Hooks, events, step content
  • [Router Adapters](references/router-adapters.md) - TanStack, React Router, Next.js
  • [Advanced Patterns](references/advanced-patterns.md) - Versions, storage, migrations

Examples

  • [Basic Flow](examples/basic-flow.tsx) - Simple 3-step onboarding
  • [Async Content](examples/waitfor-async.tsx) - waitFor patterns
  • [Lifecycle Hooks](examples/lifecycle-hooks.tsx) - UI synchronization
  • [Router Sync](examples/router-sync.tsx) - All 4 router adapters