Nasaq

ProductOnboarding

The first-run flow every Nasaq product shares: workspace → business basics → sample data → connect your AI → invite your team → done. Skippable and resumable from server state.

Code

"use client";import { Field, FieldLabel, Input, ProductOnboarding, type ProductOnboardingState } from "@fadymondy/nasaq/web";declare const state: ProductOnboardingState;declare const api: { post(path: string, body?: unknown): Promise<void> };export function Onboarding({ onExit }: { onExit: () => void }) {  return (    <ProductOnboarding      product="Matjar"      state={state}      workspace={{ content: <Field><FieldLabel>Store name</FieldLabel><Input defaultValue="3x1" /></Field> }}      business={{ content: <Field><FieldLabel>Currency</FieldLabel><Input defaultValue="EGP" /></Field> }}      onLoadSampleData={() => api.post("/api/onboarding/sample-data")}      mcp={{ server: { name: "matjar", url: "https://3x1.matjar.app/api/mcp" } }}      onInvite={(emails, role) => api.post("/api/team/invites", { emails, role })}      roles={[{ value: "staff", label: "Staff" }]}      onAction={(step, action) => api.post("/api/onboarding", { step, action })}      onExit={onExit}    />  );}

Loading & States · beta

Live examples and controls: ProductOnboarding in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/product-onboarding.json

The same first-run flow in every Nasaq product. It runs these steps in a fixed order: confirm the workspace, the business basics, load sample data, connect an AI app over MCP, and invite the team. The first two are required and the rest can be skipped. Progress lives on the server, so people resume where they left off, and "Skip setup" leaves at any point. It is built on SetupWizard; the sample-data, connect and invite steps come with their own bodies.

When to use

  • The /onboarding page a product opens after "Create business/store".

When not to use

  • A product that is not a business workspace: use SetupWizard with your own steps.
  • The dashboard reminder: use OnboardingChecklist with onboardingOpen(state).

Import

import { ProductOnboarding } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

"use client";
import { Field, FieldLabel, Input, ProductOnboarding, type ProductOnboardingState } from "@fadymondy/nasaq/web";

declare const state: ProductOnboardingState;
declare const api: { post(path: string, body?: unknown): Promise<void> };

export function Onboarding({ onExit }: { onExit: () => void }) {
  return (
    <ProductOnboarding
      product="Matjar"
      state={state}
      workspace={{ content: <Field><FieldLabel>Store name</FieldLabel><Input defaultValue="3x1" /></Field> }}
      business={{ content: <Field><FieldLabel>Currency</FieldLabel><Input defaultValue="EGP" /></Field> }}
      onLoadSampleData={() => api.post("/api/onboarding/sample-data")}
      mcp={{ server: { name: "matjar", url: "https://3x1.matjar.app/api/mcp" } }}
      onInvite={(emails, role) => api.post("/api/team/invites", { emails, role })}
      roles={[{ value: "staff", label: "Staff" }]}
      onAction={(step, action) => api.post("/api/onboarding", { step, action })}
      onExit={onExit}
    />
  );
}

Anatomy

ProductOnboarding                 data-slot="product-onboarding"
├─ SetupWizard                    data-step="workspace|business|sample-data|connect-mcp|invite"
│  ├─ workspace (required)        your form
│  ├─ business (required)         your form
│  ├─ sample-data (optional)      built-in: Load sample data → success alert
│  ├─ connect-mcp (optional)      built-in: McpConnectApps
│  ├─ invite (optional)           built-in: emails + role → onInvite
│  └─ done screen                 Open dashboard
└─ Skip setup                     dismiss + onExit

API

ProductOnboarding

PropTypeDefaultDescription
productstringrequiredProduct name in the page language.
stateProductOnboardingStaterequired{ completed, skipped?, dismissed?, finishedAt? } from GET /api/onboarding.
workspace / businessProductOnboardingStepBodyrequired{ content, ready?, title?, description? }.
onLoadSampleData() => AuthSubmitResult | PromiseOmit to drop the step.
mcpOmit<McpConnectAppsProps, "product">Omit to drop the step.
onInvite(emails, role) => AuthSubmitResult | PromiseOmit to drop the step.
roles{ value, label }[]Invite roles; the first is the default.
onAction(step, action) => AuthSubmitResult | Promiserequiredaction is complete, skip, dismiss or finish. { error } keeps the step.
onExit() => voidrequiredOpen dashboard / after Skip setup.
labels / wizardLabelspartial labelsbuilt-in EN/AR

Helpers (pure): onboardingResumeIndex(stepIds, state), onboardingOpen(state), applyOnboardingAction(state, step, action, now?) (the server's rules, for optimistic updates and tests), onboardingProgress(stepIds, state), isOptionalStep(id). Constants: PRODUCT_ONBOARDING_STEPS, REQUIRED_ONBOARDING_STEPS.

The server contract every product implements: GET /api/onboarding → state, and POST /api/onboarding { step?, action } → state. skip never overrides complete. finish sets finishedAt once.

Examples

Show the dashboard card while setup is open:

import { OnboardingChecklist, PRODUCT_ONBOARDING_STEPS, onboardingOpen, type ProductOnboardingState } from "@fadymondy/nasaq/web";

declare const state: ProductOnboardingState;
export const Resume = () =>
  onboardingOpen(state) ? (
    <OnboardingChecklist items={PRODUCT_ONBOARDING_STEPS.map((id) => ({ id, title: id, done: state.completed.includes(id) || (state.skipped ?? []).includes(id) }))} />
  ) : null;

Accessibility

KeyAction
TabMoves through the step body, then Back · Skip · Continue.
Enter / SpaceActivates the focused button.

The step heading takes focus on every step change. Errors render as role="alert".

RTL & i18n

Every built-in string has EN and AR copy. Email addresses are entered dir="ltr". Arrows mirror in RTL (from SetupWizard).

Styling & tokens

Inherits SetupWizard and McpConnectApps. Target [data-slot=product-onboarding] and [data-step].

Do / Don't

  • Do mark workspace complete on the server when the console creates the business, so people start at step 2.
  • Do keep business basics to six fields or fewer.
  • Don't add steps; put product extras on the dashboard checklist.

Lab

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

On this page