Setup assistant
A setup checklist with actions, step progress and expandable substeps.
Installation
The CLI installs the Radix or Base UI file to match your project, with what it builds on: alert, button, card, progress-indicator, progress-ring, skeleton, switch.
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- On a Setup or onboarding page that walks an admin through numbered steps, like Lightning's Setup Assistant for Sales Cloud or Service Cloud.
- When each step shows how far along it is, with a button, a link or a switch that does it.
- When a step breaks into substeps done in order, shown when the step expands.
- When a card's header counts how many steps are done.
Don't use it
- For a record's stage or status. Use Path.
- For a wizard's position, moved by Back and Next. Use Progress indicator.
- For one task's percent on its own. Use Progress ring.
- For substeps that can be done in any order inside one step. Split them into steps.
- To install or configure features in an org. The block only shows what the app reports.
Usage
import {
SetupAssistant,
SetupAssistantList,
SetupAssistantSummary,
} from "@/components/wisty/setup-assistant"SetupAssistant
├── SetupAssistantSummary
└── SetupAssistantList<SetupAssistant steps={steps} aria-label="Sales Setup Assistant">
<SetupAssistantList />
</SetupAssistant>SetupAssistantSummary shows how many steps are done, as words and a bar. Put it in your card's header and SetupAssistantList in its body, with SetupAssistant around the card and headingLevel={3} under the card's h2. Leave the summary out for a list inside an existing section.
<SetupAssistant
steps={steps}
aria-label="Sales Setup Assistant"
onAction={(action, target) => openSetupFlow(action.value, target)}
onToggleChange={(stepId, checked) => saveSetting(stepId, checked)}
>
<SetupAssistantList />
</SetupAssistant>A step is a task with a button or link, a setting with a switch, or a sequence of substeps. onAction and onToggleChange only ask for the work. Replace the step's progress, or the switch's checked, in steps once the work succeeds. A link never completes a step. For a sequence, completed counts finished substeps from the first: the next one is current, and later ones wait. value, defaultValue and onValueChange hold which sequences are open, apart from their progress.
Examples
Steps without progress
Untracked steps with no rings, a setup page, a guide and a switch, without a card or summary.
Set up Email-to-Case
Turn customer emails to your support address into cases.
Open Email-to-Case15 mins
Learn how agents use Knowledge
See how articles help agents answer common questions.
Read the Guide20 mins
Turn on Feed Tracking for cases
Show changes to a case's status and owner in its feed.
Progress not fully available
Available steps stay visible, unknown progress is named, a setting with no handler reads On as text, and no overall percentage is guessed.
No setup steps
A complete empty checklist says there are no steps to show, without claiming setup is finished.
Setup unavailable
An unavailable checklist explains what couldn't be read instead of showing an empty list.
Loading setup
Placeholder rows hold the list's shape while setup loads, without an invented completion value.
API reference
| Part | Built on | Description |
|---|---|---|
SetupAssistant | <section> (opens in a new tab) | A setup checklist's data and expanded steps, shared by its summary and list. |
SetupAssistantSummary | <div> (opens in a new tab) | How many steps are done, as words and a bar, or why that isn't known. |
SetupAssistantList | <div> (opens in a new tab) | The numbered steps, with their rings, actions and substeps. |
SetupAssistant
A setup checklist's data and expanded steps, shared by its summary and list.
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | Names the checklist, like "Sales Setup Assistant". | |
aria-labelledby | string | The id of the visible title that names the checklist. | |
steps* | readonly SetupAssistantStep[] | null | The steps as read, in order. null when they couldn't be read. | |
partial | { message: string } | never | Set when some steps couldn't be read: the notice above the ones that could. | |
unavailableMessage | never | string | Why the steps couldn't be read. Default "Setup steps aren't available." | |
loading | boolean | false | Marks the checklist busy: placeholder rows with no steps, or the steps kept while they reload. |
value | readonly string[] | The ids of the open sequences, when controlled. | |
defaultValue | readonly string[] | The ids of the sequences open at first. | |
onValueChange | (value: string[]) => void | Called with the open sequences' ids, in step order. | |
onAction | ( action: SetupAssistantButtonAction, target: SetupAssistantActionTarget ) => void | Asks the app to do a button's work. Buttons render only with it. | |
onToggleChange | (stepId: string, checked: boolean) => void | Asks the app to change a setting. Without it, settings show On or Off as text. | |
headingLevel | 2 | 3 | 4 | 5 | 6 | 2 | The step titles' heading level. Default 2, 3 under a card's h2 title. |
SetupAssistantSummary
How many steps are done, as words and a bar, or why that isn't known.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Setup progress" | Names the bar, shown above it. |
SetupAssistantButtonActiontype
A button that asks the app to do a step's work, through onAction.
| Member | Type | Default | Description |
|---|---|---|---|
type* | "button" | Draws an outline brand button. | |
value* | string | Identifies the action in onAction: "confirm-mapping". | |
label* | string | The button's words: "Confirm mapping". | |
disabled | boolean | Shows the button but doesn't let it run. |
SetupAssistantLinkActiontype
A link to a setup page, an article or a video. Following it never completes a step.
| Member | Type | Default | Description |
|---|---|---|---|
type* | "link" | Navigates with href, without calling onAction. | |
value* | string | Identifies the action: "manage-users". | |
label* | string | The link's words: "View on Trailhead". | |
href* | string | Where the link goes. | |
variant | "link" | "outline-brand" | "link" draws text, "outline-brand" a button that opens a setup page. Default "link". | |
disabled | boolean | Shows the link as weak text, or a disabled button, that goes nowhere. |
SetupAssistantToggletype
A switch that turns a setting on or off, through onToggleChange.
type SetupAssistantToggle = {
type: "toggle"
value: string
label: string
disabled?: boolean
} & (
| {
checked: boolean
unavailableLabel?: never
}
| {
checked: null
unavailableLabel: string
}
)SetupAssistantControltype
type SetupAssistantControl =
| SetupAssistantButtonAction
| SetupAssistantLinkAction
| SetupAssistantToggleSetupAssistantActionTargettype
What an action is for: a step, or one of a sequence's substeps.
| Member | Type | Default | Description |
|---|---|---|---|
stepId* | string | The step's id. | |
substepId | string | The substep's id, when the action is a substep's. |
SetupAssistantTaskProgresstype
A task's progress. Unknown never counts as not started.
type SetupAssistantTaskProgress =
| { value: "untracked" }
| { value: "not-started"; label: string }
| { value: "in-progress"; label: string; percent: number | null }
| { value: "complete"; label: string }
| { value: "unknown"; label: string }SetupAssistantSequenceProgresstype
A sequence's progress: how many substeps are done, counted from the first.
type SetupAssistantSequenceProgress =
| { value: "known"; completed: number }
| { value: "unknown"; label: string }SetupAssistantSubsteptype
One substep of a sequence. Substeps are done in order.
| Member | Type | Default | Description |
|---|---|---|---|
id* | string | Unique within its sequence. | |
label* | string | What to do: "Confirm field mapping". | |
description | string | A line under the label. | |
action | SetupAssistantButtonAction | SetupAssistantLinkAction | A button or link for the substep. Later substeps' actions wait for earlier ones. |
SetupAssistantTasktype
A step done in one go, with an optional button or link.
type SetupAssistantTask = SetupAssistantStepContent & {
kind: "task"
progress: SetupAssistantTaskProgress
action?: SetupAssistantButtonAction | SetupAssistantLinkAction
}SetupAssistantSettingtype
A step that turns a setting on with a switch.
type SetupAssistantSetting = SetupAssistantStepContent & {
kind: "setting"
tracked: boolean
action: SetupAssistantToggle
}SetupAssistantSequencetype
A step that expands into substeps done in order. Its ring counts them.
type SetupAssistantSequence = SetupAssistantStepContent & {
kind: "sequence"
progress: SetupAssistantSequenceProgress
substeps: readonly [SetupAssistantSubstep, ...SetupAssistantSubstep[]]
}SetupAssistantSteptype
type SetupAssistantStep =
| SetupAssistantTask
| SetupAssistantSetting
| SetupAssistantSequenceSetupAssistantReadtype
The steps as read: a list, partial when some couldn't be read, or null when none could.
type SetupAssistantRead =
| {
steps: readonly SetupAssistantStep[]
partial?: { message: string }
unavailableMessage?: never
}
| {
steps: null
partial?: never
unavailableMessage?: string
}Accessibility
- Each step's title is a heading at
headingLevel, 2 by default. Set it one below the heading the list sits under. - A sequence opens from its chevron and from its title. Both report
aria-expandedand point at the substeps witharia-controls. - Each ring is named "Step 2: Prepare your account data" and described by the step's progress label. Unknown progress shows its label on the page, and a setting that couldn't be read shows its
unavailableLabelin place of the switch. - A switch is named by its toggle's
label. The On and Off beside it are hidden from screen readers, which hear the switch's state. WithoutonToggleChangethere's no switch, and screen readers hear the label before the On or Off text. - A link with
disabled, or a later substep's link, is plain text with nohref, so it takes no focus. With the button look it's a disabled button. - If your app closes an open sequence while focus is inside it, move focus to its title first.
Responsive behavior
- The block takes its container's width. Below 32rem, a step's action and estimate move under its description.
- Titles, descriptions and substeps wrap instead of truncating. Give the card a
max-w-*so lines stay readable on a wide page.
Rules
- Keep completion in
steps, written by your app. Nothing in the block completes a step by itself. - Pass an unknown progress with a label when you couldn't read it, never
not-startedor 0. For a setting, passchecked: nullwith anunavailableLabel, neverfalse. Unknown never counts as done or not done. - Pass
partialwith a message when only some steps could be read, andsteps={null}when none could, never a shorter or empty list: an empty list says there are none. - Pass
loadingwhile the steps load, never an empty list. To reload steps already shown, keep passing them withloading: the rows stay, and the summary says progress is updating instead of showing a bar that may be stale. - Give every step a unique
id, and every substep one unique within its step. Ids keep the open sequences and callbacks pointed at the right row when steps reorder. estimatedTimeis a label. It never weighs progress, and the summary counts finished steps.- Buttons render only with
onAction, and switches only withonToggleChange. Without it, a setting shows its confirmed state as On or Off text. - Never pass
asChildorrender.