PParable
All components

Intro Disclosure

Interactive

A first-run onboarding sequence: a stepped dialog card with title, body, optional media, Back/Next, a clickable progress-dots row, and Skip, where steps cross-fade and slide in the travel direction while the card height springs to fit the incoming content. It is a real role="dialog" with focus trap, Escape-to-skip, and focus return; under prefers-reduced-motion the slide, blur, and height morph are dropped and steps swap instantly.

Inspired by Cult UI — Intro Disclosure / Onboarding (free, MIT) — independently built, not affiliated. Attribution policy

Installation

npx shadcn@latest add https://parable-three.vercel.app/r/intro-disclosure.json

Runs the shadcn CLI — the component source is copied intocomponents/parable/intro-disclosure.tsx. You own it from there.

Usage

The exact code rendering the preview above.

<div className="relative flex h-[440px] w-full max-w-[380px] items-center justify-center overflow-hidden rounded-2xl border border-white/10 bg-[#0f0f10]">
    <div
      aria-hidden
      className="pointer-events-none absolute inset-0"
      style={{
        backgroundImage:
          "radial-gradient(circle at 28% 18%, rgba(139,92,246,0.20), transparent 55%), radial-gradient(circle at 82% 84%, rgba(34,211,238,0.14), transparent 55%)",
      }}
    />
    <IntroDisclosure
      defaultOpen
      steps={[
        {
          title: "Welcome to Parable",
          body: "A living registry of motion-first React components — copy one file into your app and own it outright.",
          media: (
            <div className="flex h-28 items-center justify-center bg-gradient-to-br from-violet-500/30 via-fuchsia-500/20 to-transparent">
              <Sparkles className="text-violet-200" />
            </div>
          ),
        },
        {
          title: "Themed to your brand",
          body: "Every component ships with --pb-* tokens, so accent and surface colours follow your own design system.",
          media: (
            <div className="flex h-28 items-center justify-center bg-gradient-to-br from-fuchsia-500/30 via-amber-400/15 to-transparent">
              <Palette className="text-fuchsia-200" />
            </div>
          ),
        },
        {
          title: "Ship in minutes",
          body: "Reduced-motion safe, keyboard operable, and SSR-ready out of the box. Press Get started to finish the tour.",
          media: (
            <div className="flex h-28 items-center justify-center bg-gradient-to-br from-cyan-400/25 via-violet-500/20 to-transparent">
              <Rocket className="text-cyan-200" />
            </div>
          ),
        },
      ]}
    />
  </div>

Props

IntroDisclosureProps extends Omit< React.HTMLAttributes<HTMLDivElement>, | "children" | "title" | "onAnimationStart" | "onAnimationEnd" | "onAnimationIteration" | "onDrag" | "onDragStart" | "onDragEnd" >

PropTypeDefaultDescription
steps*IntroStep[]Ordered steps the tour walks through.
openbooleanControlled open state. Pair with `onOpenChange`.
defaultOpenbooleanfalseUncontrolled initial open state.
onOpenChange(open: boolean) => voidFires with the next open state on Skip, Escape, backdrop, or completion.
stepnumberControlled active step index. Pair with `onStepChange`.
defaultStepnumber0Uncontrolled initial step index.
onStepChange(step: number) => voidFires with the next step index on Back / Next / dot navigation.
onComplete() => voidFires when the primary button is pressed on the final step.
accentstring"#8b5cf6"Accent hex — primary button, active dot, focus ring. Mirrors `--pb-violet`.
backgroundstring"#0f0f10"Card surface colour. Mirrors the site `--pb-ink` token.
nextLabelReact.ReactNode"Next"Label for the advance button on non-final steps.
backLabelReact.ReactNode"Back"Label for the back button.
skipLabelReact.ReactNode"Skip"Label for the dismiss button.
doneLabelReact.ReactNode"Get started"Label for the primary button on the final step.
classNamestringExtra classes on the dialog card.

npm dependencies

  • motion