0.2.0

Every aspect of the tour — from step definitions to the appearance of each UI element — is controlled through a single configuration object, BordaConfig, passed to borda.mount(). The only required field is steps; everything else has a sensible default or can be disabled entirely.

import { useBorda, ComponentPlacement, BordaTourProgressVariant } from '@retoo/borda';

import '@retoo/borda/styles';

const borda = useBorda();

const instance = await borda.mount({
  steps: [
    {
      target: '#nav-sidebar',
      title: 'Navigation',
      description: 'Every section is one click away.',
      placement: ComponentPlacement.MIDDLE_END,
    },
    {
      target: '#search-bar',
      title: 'Search',
      description: 'Find any page or setting instantly.',
      placement: ComponentPlacement.BOTTOM_CENTER,
    },
    {
      target: '#main-content',
      title: 'Main area',
      description: 'Your primary content lives here.',
      placement: ComponentPlacement.MIDDLE_START,
    },
    {
      target: '#user-menu',
      title: 'Account',
      description: 'Manage your profile and preferences.',
      placement: ComponentPlacement.BOTTOM_END,
    },
  ],
  tourProgress: {
    variant: BordaTourProgressVariant.DOTS,
  },
});

Config structure

BordaConfig combines component overrides and feature configs:

KeyDescription
stepsArray of step definitions. Required.
sizeWidget size — xs, sm, md, lg, xl, xxl
shapeWidget shape — circle, square, portrait, landscape
containerOuter container props — custom classes/styles
tourOverlaySpotlight overlay. Pass false to disable.
tourTooltipTooltip with title/description. Pass false to disable.
tourImageImage inside the tooltip. Pass false to disable.
tourButtonsPrev/next/finish/skip buttons. Pass false to disable.
tourProgressProgress indicator. Pass false to disable.
tourSkip"Don't show again" checkbox. Pass false to disable.
closeButtonClose button. Pass false to disable.
tourTour behavior — startStep, lifecycle callbacks, keyboard control
visibilityInitial visibility state and animation
responsiveBreakpoint-specific overrides
scrollSmooth scroll to target. Pass false to disable.
skipSkip feature persistence. Pass false to disable.
animationTooltip/overlay animations. Pass false to disable.

Disabling components

Pass false to any component key to remove it from the tour entirely:

Compare this to the live demo above the fold: that one shows every component enabled with progress dots; this one strips them all down to the spotlight and tooltip text.

await borda.mount({
  steps: [
    {
      target: '#announcement-banner',
      title: 'New feature available',
      description: 'A one-off spotlight with no navigation chrome — pair it with your own dismiss logic.',
      placement: ComponentPlacement.BOTTOM_CENTER,
    },
  ],
  tourSkip: false,
  tourButtons: false,
  tourProgress: false,
  closeButton: false,
});

This is different from hiding — a disabled component is never rendered in the DOM.

Runtime updates

After mount, modify any config property through the instance — useful for reacting to screen size, user plan, or A/B test variant without unmounting:

import { useBorda, ComponentSize } from '@retoo/borda';

import '@retoo/borda/styles';

const borda = useBorda();

const instance = await borda.mount({
  steps: [
    {
      target: '#trial-banner',
      title: "You're on a free trial",
      description: 'Upgrade any time from account settings.',
      placement: 'bottom-center',
    },
  ],
});

// Deep merge — only the specified fields are updated
// e.g. enlarge the widget and hide skip once the user is on their 3rd session
instance.config.mergeConfig({
  size: ComponentSize.LG,
  tourButtons: { skip: false },
});

// Full replacement — e.g. switch to a different flow after the user upgrades
instance.config.setConfig({
  steps: [
    {
      target: '#billing-section',
      title: "You're on the Pro plan",
      description: 'Manage your subscription and invoices here.',
      placement: 'bottom-center',
    },
  ],
});

Both methods trigger a reactive update — the widget re-renders immediately without remounting.

Customization

Most components accept customClasses and customStyles for visual overrides without modifying the source. Classes are merged with the defaults; styles are applied as inline CSS.

await borda.mount({
  steps: [
    {
      target: '#cta-button',
      title: 'Branded tooltip',
      description: 'Custom classes and inline styles, no source modification required.',
      placement: ComponentPlacement.BOTTOM_CENTER,
    },
  ],
  tourTooltip: {
    customClasses: {
      root: 'my-tooltip',
      title: 'text-lg font-bold',
    },
    customStyles: {
      root: {
        borderRadius: '4px',
        background: '#fafaf9',
        border: '2px solid #18181b',
      },
    },
  },
});