Docs Components Advanced

Wizard

React example follows below.
ts
/**
* Wizard's pinned demo state (CSP-D3).
*
* `step: 1` of four pins the rail *mid-flow* so all three step states render
* in one shot — step 0 "done" (filled tile + check glyph), step 1 "active"
* (outlined tile), steps 2-3 "upcoming" (muted) — and the footer shows both
* controls at once (Back visible rather than `invisible`, Next still reading
* "Next" rather than the near-the-end "Confirm"/"Finish" labels).
*
* `content` is a plain string on purpose: React and Solid type it as a node,
* Vue/Angular/Svelte as a string, so the one shape every adapter renders
* identically is text. Rich per-step markup is each framework's own seam and
* would make the five demos diverge.
*/
const wizardFixture = {
id: "wizard",
step: 1,
backLabel: "Back",
steps: [
{
eyebrow: "Step 01",
label: "Account",
content: "Your workspace owner and billing contact.",
},
{
eyebrow: "Step 02",
label: "Workspace",
content: "Name the workspace and pick its region.",
},
{
eyebrow: "Step 03",
label: "Team",
content: "Invite the people who need access on day one.",
},
{
eyebrow: "Step 04",
label: "Review",
content: "Check everything over, then create the workspace.",
},
],
} satisfies {
id: string;
step: number;
backLabel: string;
steps: { eyebrow: string; label: string; content: string }[];
};
import { Wizard } from "@grassroot/ui-react/advanced";
export default function WizardDemo() {
return (
<div>
<Wizard
steps={wizardFixture.steps}
defaultStep={wizardFixture.step}
backLabel={wizardFixture.backLabel}
/>
</div>
);
}
ts
<script setup lang="ts">
import { ref } from "vue";
/**
* Wizard's pinned demo state (CSP-D3).
*
* `step: 1` of four pins the rail *mid-flow* so all three step states render
* in one shot — step 0 "done" (filled tile + check glyph), step 1 "active"
* (outlined tile), steps 2-3 "upcoming" (muted) — and the footer shows both
* controls at once (Back visible rather than `invisible`, Next still reading
* "Next" rather than the near-the-end "Confirm"/"Finish" labels).
*
* `content` is a plain string on purpose: React and Solid type it as a node,
* Vue/Angular/Svelte as a string, so the one shape every adapter renders
* identically is text. Rich per-step markup is each framework's own seam and
* would make the five demos diverge.
*/
const wizardFixture = {
id: "wizard",
step: 1,
backLabel: "Back",
steps: [
{
eyebrow: "Step 01",
label: "Account",
content: "Your workspace owner and billing contact.",
},
{
eyebrow: "Step 02",
label: "Workspace",
content: "Name the workspace and pick its region.",
},
{
eyebrow: "Step 03",
label: "Team",
content: "Invite the people who need access on day one.",
},
{
eyebrow: "Step 04",
label: "Review",
content: "Check everything over, then create the workspace.",
},
],
} satisfies {
id: string;
step: number;
backLabel: string;
steps: { eyebrow: string; label: string; content: string }[];
};
import { Wizard } from "@grassroot/ui-vue";
// `v-model:step` is Vue's unified controlled/initial seam — React's
// `defaultStep` folds into the same prop (see contracts/divergences.json),
// so the fixture's pinned step seeds this ref.
const step = ref(wizardFixture.step);
</script>
<template>
<div>
<Wizard
v-model:step="step"
:steps="wizardFixture.steps"
:back-label="wizardFixture.backLabel"
/>
</div>
</template>
ts
import { Component } from "@angular/core";
/**
* Wizard's pinned demo state (CSP-D3).
*
* `step: 1` of four pins the rail *mid-flow* so all three step states render
* in one shot — step 0 "done" (filled tile + check glyph), step 1 "active"
* (outlined tile), steps 2-3 "upcoming" (muted) — and the footer shows both
* controls at once (Back visible rather than `invisible`, Next still reading
* "Next" rather than the near-the-end "Confirm"/"Finish" labels).
*
* `content` is a plain string on purpose: React and Solid type it as a node,
* Vue/Angular/Svelte as a string, so the one shape every adapter renders
* identically is text. Rich per-step markup is each framework's own seam and
* would make the five demos diverge.
*/
const wizardFixture = {
id: "wizard",
step: 1,
backLabel: "Back",
steps: [
{
eyebrow: "Step 01",
label: "Account",
content: "Your workspace owner and billing contact.",
},
{
eyebrow: "Step 02",
label: "Workspace",
content: "Name the workspace and pick its region.",
},
{
eyebrow: "Step 03",
label: "Team",
content: "Invite the people who need access on day one.",
},
{
eyebrow: "Step 04",
label: "Review",
content: "Check everything over, then create the workspace.",
},
],
} satisfies {
id: string;
step: number;
backLabel: string;
steps: { eyebrow: string; label: string; content: string }[];
};
import { GrassrootWizard } from "@grassroot/ui-angular";
// Every input is a `[property]` binding, never a static attribute — Angular
// leaves static template attributes on the host element in the rendered DOM,
// where the other four frameworks have nothing.
@Component({
selector: "app-wizard-demo",
standalone: true,
imports: [GrassrootWizard],
template: `
<div>
<grassroot-wizard [steps]="steps" [(step)]="step" [backLabel]="backLabel" />
</div>
`,
})
export class WizardDemoComponent {
protected readonly steps = wizardFixture.steps;
// `step` is a two-way `model()` — Angular's unified controlled/initial
// seam for React's `step`/`defaultStep` pair, seeded from the fixture.
protected step = wizardFixture.step;
protected readonly backLabel = wizardFixture.backLabel;
}
export default WizardDemoComponent;
ts
<script lang="ts">
/**
* Wizard's pinned demo state (CSP-D3).
*
* `step: 1` of four pins the rail *mid-flow* so all three step states render
* in one shot — step 0 "done" (filled tile + check glyph), step 1 "active"
* (outlined tile), steps 2-3 "upcoming" (muted) — and the footer shows both
* controls at once (Back visible rather than `invisible`, Next still reading
* "Next" rather than the near-the-end "Confirm"/"Finish" labels).
*
* `content` is a plain string on purpose: React and Solid type it as a node,
* Vue/Angular/Svelte as a string, so the one shape every adapter renders
* identically is text. Rich per-step markup is each framework's own seam and
* would make the five demos diverge.
*/
const wizardFixture = {
id: "wizard",
step: 1,
backLabel: "Back",
steps: [
{
eyebrow: "Step 01",
label: "Account",
content: "Your workspace owner and billing contact.",
},
{
eyebrow: "Step 02",
label: "Workspace",
content: "Name the workspace and pick its region.",
},
{
eyebrow: "Step 03",
label: "Team",
content: "Invite the people who need access on day one.",
},
{
eyebrow: "Step 04",
label: "Review",
content: "Check everything over, then create the workspace.",
},
],
} satisfies {
id: string;
step: number;
backLabel: string;
steps: { eyebrow: string; label: string; content: string }[];
};
import { Wizard } from "@grassroot/ui-svelte";
</script>
<div>
<Wizard
steps={wizardFixture.steps}
defaultStep={wizardFixture.step}
backLabel={wizardFixture.backLabel}
/>
</div>
ts
/** @jsxImportSource solid-js */
/**
* Wizard's pinned demo state (CSP-D3).
*
* `step: 1` of four pins the rail *mid-flow* so all three step states render
* in one shot — step 0 "done" (filled tile + check glyph), step 1 "active"
* (outlined tile), steps 2-3 "upcoming" (muted) — and the footer shows both
* controls at once (Back visible rather than `invisible`, Next still reading
* "Next" rather than the near-the-end "Confirm"/"Finish" labels).
*
* `content` is a plain string on purpose: React and Solid type it as a node,
* Vue/Angular/Svelte as a string, so the one shape every adapter renders
* identically is text. Rich per-step markup is each framework's own seam and
* would make the five demos diverge.
*/
const wizardFixture = {
id: "wizard",
step: 1,
backLabel: "Back",
steps: [
{
eyebrow: "Step 01",
label: "Account",
content: "Your workspace owner and billing contact.",
},
{
eyebrow: "Step 02",
label: "Workspace",
content: "Name the workspace and pick its region.",
},
{
eyebrow: "Step 03",
label: "Team",
content: "Invite the people who need access on day one.",
},
{
eyebrow: "Step 04",
label: "Review",
content: "Check everything over, then create the workspace.",
},
],
} satisfies {
id: string;
step: number;
backLabel: string;
steps: { eyebrow: string; label: string; content: string }[];
};
import { Wizard } from "@grassroot/ui-solid";
export default function WizardDemo() {
return (
<div>
<Wizard
steps={wizardFixture.steps}
defaultStep={wizardFixture.step}
backLabel={wizardFixture.backLabel}
/>
</div>
);
}

Installation

API Reference

Import

import { Wizard } from "@grassroot/ui-react/advanced";

Props

Prop
Type
Default
Requirement
Description
steps
WizardStep[]
required
step
number | undefined
optional
Controlled current index.
defaultStep
number | undefined
0
optional
Uncontrolled initial index.
onStepChange
((next: number) => void) | undefined
optional
Fired with the new index when the step changes.
onFinish
(() => void) | undefined
optional
Fired when Next is pressed on the last step.
backLabel
string | undefined
"Back"
optional
Back button label.
Prop
steps
Type
WizardStep[]
Default
Requirement
required
Description
Prop
step
Type
number | undefined
Default
Requirement
optional
Description
Controlled current index.
Prop
defaultStep
Type
number | undefined
Default
0
Requirement
optional
Description
Uncontrolled initial index.
Prop
onStepChange
Type
((next: number) => void) | undefined
Default
Requirement
optional
Description
Fired with the new index when the step changes.
Prop
onFinish
Type
(() => void) | undefined
Default
Requirement
optional
Description
Fired when Next is pressed on the last step.
Prop
backLabel
Type
string | undefined
Default
"Back"
Requirement
optional
Description
Back button label.

Events

EventPayload
onStepChange((next: number) => void) | undefined
onFinish(() => void) | undefined

Native attributes

Standard DOM and ARIA attributes not listed above spread onto the root element.

Import

import { ref } from "vue";
import { Wizard } from "@grassroot/ui-vue";

Props

Prop
Type
Default
Requirement
steps
WizardStepItem[]
required
step
number | undefined
optional
backLabel
string | undefined
"Back"
optional
Prop
steps
Type
WizardStepItem[]
Default
Requirement
required
Prop
step
Type
number | undefined
Default
Requirement
optional
Prop
backLabel
Type
string | undefined
Default
"Back"
Requirement
optional

Events

EventPayload
update:step[step: number]
finish[]

Content regions

  • step

Import

import { Component } from "@angular/core";
import { GrassrootWizard } from "@grassroot/ui-angular";

Props

Prop
Type
Default
Requirement
steps
readonly WizardStepItem[]
required
step
number
0
optional
backLabel
string
"Back"
optional
Prop
steps
Type
readonly WizardStepItem[]
Default
Requirement
required
Prop
step
Type
number
Default
0
Requirement
optional
Prop
backLabel
Type
string
Default
"Back"
Requirement
optional

Events

EventPayload
stepChangenumber
finishvoid

Import

import { Wizard } from "@grassroot/ui-svelte";

Props

Prop
Type
Default
Requirement
steps
WizardStepItem[]
required
step
number
optional
defaultStep
number
0
optional
backLabel
string
"Back"
optional
onStepChange
(step: number) => void
optional
onFinish
() => void
optional
className
string
optional
Prop
steps
Type
WizardStepItem[]
Default
Requirement
required
Prop
step
Type
number
Default
Requirement
optional
Prop
defaultStep
Type
number
Default
0
Requirement
optional
Prop
backLabel
Type
string
Default
"Back"
Requirement
optional
Prop
onStepChange
Type
(step: number) => void
Default
Requirement
optional
Prop
onFinish
Type
() => void
Default
Requirement
optional
Prop
className
Type
string
Default
Requirement
optional

Events

EventPayload
onStepChange(step: number) => void
onFinish() => void

Content regions

  • children

Import

import { Wizard } from "@grassroot/ui-solid";

Props

Prop
Type
Default
Requirement
steps
WizardStep[]
required
step
number
optional
defaultStep
number
0
optional
onStepChange
(next: number) => void
optional
onFinish
() => void
optional
backLabel
string
"Back"
optional
className
string
optional
Prop
steps
Type
WizardStep[]
Default
Requirement
required
Prop
step
Type
number
Default
Requirement
optional
Prop
defaultStep
Type
number
Default
0
Requirement
optional
Prop
onStepChange
Type
(next: number) => void
Default
Requirement
optional
Prop
onFinish
Type
() => void
Default
Requirement
optional
Prop
backLabel
Type
string
Default
"Back"
Requirement
optional
Prop
className
Type
string
Default
Requirement
optional

Events

EventPayload
onStepChange(next: number) => void
onFinish() => void