Nasaq
Components

SetupWizard

Multi-step first-run wizard with a server-decided completion gate, plus a guided connect step that waits live for an agent to enroll.

PreviewOpen ↗

Code

import { SetupWizard } from "@fadymondy/nasaq/web";export function Setup({ done, canFinish }: { done: string[]; canFinish: boolean }) {  return (    <SetupWizard      title="Set up your workspace"      completed={done}      canFinish={canFinish}      gateMessage={canFinish ? undefined : "Connect an agent first."}      steps={[        { id: "name", title: "Name", content: <input aria-label="Name" /> },        { id: "agent", title: "Agent", content: <p>Run the command.</p> },      ]}      onStepComplete={async (id) => api.saveStep(id)}      onFinish={async () => api.finish()}    />  );}declare const api: { saveStep(id: string): Promise<void>; finish(): Promise<void> };

Onboarding · beta

Live examples and controls: SetupWizard in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/setup-wizard.json

Owns the order, gating and completion of a first-run flow. Each step body is your own form. The server decides when setup may finish: pass canFinish and completed from it. AgentEnrollWait is a ready-made step body for connecting an agent: it shows the command, then waits live until the agent checks in.

When to use

  • First-run setup of a workspace, project or integration.
  • Guided connection of a machine or agent.

When not to use

  • A single form: use a form.
  • Ongoing settings: use a settings page.

Import

import { AgentEnrollWait, SetupWizard } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

import { SetupWizard } from "@fadymondy/nasaq/web";

export function Setup({ done, canFinish }: { done: string[]; canFinish: boolean }) {
  return (
    <SetupWizard
      title="Set up your workspace"
      completed={done}
      canFinish={canFinish}
      gateMessage={canFinish ? undefined : "Connect an agent first."}
      steps={[
        { id: "name", title: "Name", content: <input aria-label="Name" /> },
        { id: "agent", title: "Agent", content: <p>Run the command.</p> },
      ]}
      onStepComplete={async (id) => api.saveStep(id)}
      onFinish={async () => api.finish()}
    />
  );
}

declare const api: { saveStep(id: string): Promise<void>; finish(): Promise<void> };

Anatomy

SetupWizard                   data-slot="setup-wizard"
├─ header (title, description)
├─ Stepper rail (md+) | Progress bar (mobile)
├─ current step: title, description, Optional badge, content
├─ error / gate message      role="alert"
├─ Back · Skip · Continue | Finish
└─ done screen               title, description, doneAction

API

SetupWizard: div props (except children, title) plus:

PropTypeDefaultDescription
stepsSetupStep[]required{ id, title, description?, optional?, ready?, content }.
current / defaultCurrent / onCurrentChangeZero-based step.
completedstring[]Step ids the server counts done. Required steps missing here block Finish.
onStepComplete(id) => AuthSubmitResult | PromiseRuns on Continue. { error } keeps the step.
canFinish / gateMessageboolean / stringtrueThe server verdict, and the reason if false.
onFinish() => AuthSubmitResult | Promiserequired
title, description, doneTitle, doneDescription, doneAction, labels

AgentEnrollWait: command, status (waiting, connected, timeout, failed), agent ({ name, host, version, system }), elapsed, error, onRetry, hint, labels. Poll on the host and feed it.

Examples

A step that holds Continue until the agent connects

import { AgentEnrollWait, type SetupStep } from "@fadymondy/nasaq/web";

export const step = (status: "waiting" | "connected"): SetupStep => ({
  id: "agent",
  title: "Connect an agent",
  ready: status === "connected",
  content: <AgentEnrollWait command="curl -fsSL https://get.example.com | sh" status={status} />,
});

Accessibility

  • The rail is a list with aria-current="step". Moving forward or back focuses the new step heading.
  • Status changes in AgentEnrollWait are announced politely; errors use role="alert".
  • Buttons show a spinner and aria-busy while a step saves.

RTL & i18n

  • English and Arabic are built in; pass labels to override.
  • Back and Continue arrows mirror; the command is always left to right and copyable.

Styling & tokens

  • Built from Stepper, Progress, Button, Alert, CopyField and Spinner; tokens only.

Do / Don't

  • Do let the server, not the client, decide when setup is complete.
  • Do mark truly optional steps optional.
  • Don't hide why Finish is blocked: set gateMessage.
  • Don't poll faster than every couple of seconds.

Lab

https://docs.nasaqui.com/?path=/docs/components-onboarding-pages-setup-wizard--docs

On this page