Headless usage

Build your own overlay with useTour().

When to go headless

@cairnkit/ui is one opinion about how a tour should look. If you have a design system and want the tour to be part of it, drop the package and drive the engine yourself.

@cairnkit/react ships no CSS and renders nothing on its own — everything below works without ui installed.

useTour()

PropTypeDefaultDescription
flowTourFlow | nullThe running flow, or null.
stepTourStep | nullThe current step.
stepIndexnumberZero-based.
elementHTMLElement | nullThe resolved DOM node.
rectTargetRect | nullLive viewport rect, tracked on rAF.
status"resolving" | "ready" | "missing"Anchor resolution state.
isPausedbooleanOn a route this flow does not cover.
isLastStepbooleanWhether Next should read as Done.
showNextbooleanFalse when the step needs a real action.
showBeaconbooleanWhether to draw the pulsing dot.
advance / back / skip() => voidStep controls.
start / stop(flowId?) => voidStart a flow, or end the current one.

A minimal overlay

"use client";
import { useTour, useStepCopy } from "@cairnkit/react";

export function MyOverlay() {
  const tour = useTour();
  const { title, body } = useStepCopy(tour.flow, tour.step);

  if (!tour.flow || !tour.step || tour.isPaused) return null;

  return (
    <div style={{ position: "fixed", inset: 0, pointerEvents: "none" }}>
      {tour.rect && (
        <div
          style={{
            position: "absolute",
            top: tour.rect.top - 8,
            left: tour.rect.left - 8,
            width: tour.rect.width + 16,
            height: tour.rect.height + 16,
            boxShadow: "0 0 0 2px #4f46e5, 0 0 0 9999px rgb(0 0 0 / .6)",
            borderRadius: tour.rect.radius + 4,
          }}
        />
      )}

      <div style={{ pointerEvents: "auto" /* your card */ }}>
        <h2>{title}</h2>
        <p>{body}</p>
        <button onClick={tour.skip}>Skip</button>
        {tour.showNext && <button onClick={tour.advance}>Next</button>}
      </div>
    </div>
  );
}

Reusing individual pieces

@cairnkit/ui also exports its parts, so you can keep the spotlight and replace only the card.

import { Spotlight, StepCard, ProgressRail, Launcher } from "@cairnkit/ui";