Navigation
Stepper / Multi-step Form
Numbered steps that split a form into panels, with Back and Next buttons and validation that your code controls.
| Class name | Type | Description |
|---|---|---|
stepperplf:stepper | Component | Wraps the steps, panels and buttons |
stepper-listplf:stepper-list | Part | The ordered list of steps |
stepper-itemplf:stepper-item | Part | A step's list item |
stepper-stepplf:stepper-step | Part | A step's button |
stepper-markerplf:stepper-marker | Part | The step's number, written by CSS while it is empty |
stepper-contentplf:stepper-content | Part | Holds the label and state |
stepper-labelplf:stepper-label | Part | The step's name |
stepper-stateplf:stepper-state | Part | The step's state, in muted text |
stepper-panelplf:stepper-panel | Part | A step's panel |
stepper-headingplf:stepper-heading | Part | The panel's heading; shows focus |
stepper-actionsplf:stepper-actions | Part | The Back and Next row |
stepper-backplf:stepper-back | Part | The Back button, beside btn |
stepper-nextplf:stepper-next | Part | The Next button, beside btn |
Default
Author every panel visible and Back and Next hidden: the script hides the inactive panels and shows the buttons, so the whole form shows and submits without JavaScript.
<form class="flex flex-col gap-4">
<div class="stepper" data-plf-stepper>
<ol class="stepper-list" aria-label="Workspace setup steps" role="list">
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Account</span>
<span class="stepper-state" data-plf-stepper-state-label>Current step</span>
</span>
</button>
</li>
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Workspace</span>
<span class="stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Review</span>
<span class="stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
</ol>
<progress class="progress" value="1" max="3" aria-label="Workspace setup position">Step 1 of 3</progress>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Account information</h3>
<div class="field">
<label class="field-label" for="setup-name">Full name</label>
<input class="input" id="setup-name" name="full-name" type="text" autocomplete="name" required>
</div>
<div class="field">
<label class="field-label" for="setup-email">Email address</label>
<input class="input" id="setup-email" name="email" type="email" autocomplete="email" required>
</div>
</section>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Workspace details</h3>
<div class="field">
<label class="field-label" for="setup-workspace">Workspace name</label>
<input class="input" id="setup-workspace" name="workspace" type="text" required>
</div>
<div class="field">
<label class="field-label" for="setup-team-size">Team size</label>
<select class="select" id="setup-team-size" name="team-size" data-plf-select>
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</select>
</div>
</section>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Review your workspace</h3>
<p>Check your details, then create the workspace.</p>
<div><button class="btn btn-primary" type="submit">Create workspace</button></div>
</section>
<div class="stepper-actions">
<button class="btn btn-outline stepper-back" type="button" data-plf-stepper-back hidden>Back</button>
<button class="btn btn-primary stepper-next" type="button" data-plf-stepper-next hidden>Next</button>
</div>
</div>
<div><button class="btn btn-outline" type="reset">Reset setup</button></div>
</form><form class="plf:flex plf:flex-col plf:gap-4">
<div class="plf:stepper" data-plf-stepper>
<ol class="plf:stepper-list" aria-label="Workspace setup steps" role="list">
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Account</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Current step</span>
</span>
</button>
</li>
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Workspace</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Review</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
</ol>
<progress class="plf:progress" value="1" max="3" aria-label="Workspace setup position">Step 1 of 3</progress>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Account information</h3>
<div class="plf:field">
<label class="plf:field-label" for="setup-name">Full name</label>
<input class="plf:input" id="setup-name" name="full-name" type="text" autocomplete="name" required>
</div>
<div class="plf:field">
<label class="plf:field-label" for="setup-email">Email address</label>
<input class="plf:input" id="setup-email" name="email" type="email" autocomplete="email" required>
</div>
</section>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Workspace details</h3>
<div class="plf:field">
<label class="plf:field-label" for="setup-workspace">Workspace name</label>
<input class="plf:input" id="setup-workspace" name="workspace" type="text" required>
</div>
<div class="plf:field">
<label class="plf:field-label" for="setup-team-size">Team size</label>
<select class="plf:select" id="setup-team-size" name="team-size" data-plf-select>
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</select>
</div>
</section>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Review your workspace</h3>
<p>Check your details, then create the workspace.</p>
<div><button class="plf:btn plf:btn-primary" type="submit">Create workspace</button></div>
</section>
<div class="plf:stepper-actions">
<button class="plf:btn plf:btn-outline plf:stepper-back" type="button" data-plf-stepper-back hidden>Back</button>
<button class="plf:btn plf:btn-primary plf:stepper-next" type="button" data-plf-stepper-next hidden>Next</button>
</div>
</div>
<div><button class="plf:btn plf:btn-outline" type="reset">Reset setup</button></div>
</form>import {
Button, Field, Input, Select, Stepper, StepperActions, StepperBack, StepperContent, StepperHeading, StepperItem, StepperLabel,
StepperList, StepperMarker, StepperNext, StepperPanel, StepperProgress, StepperState, StepperStep,
} from '@pelatform/react';
const steps = ['Account', 'Workspace', 'Review'];
export function Example() {
return (
<form className="flex flex-col gap-4">
<Stepper>
<StepperList aria-label="Workspace setup steps">
{steps.map(label => (
<StepperItem key={label}>
<StepperStep>
<StepperMarker />
<StepperContent>
<StepperLabel>{label}</StepperLabel>
<StepperState />
</StepperContent>
</StepperStep>
</StepperItem>
))}
</StepperList>
<StepperProgress aria-label="Workspace setup position" />
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Account information</StepperHeading>
<Field label="Full name">
<Input name="full-name" type="text" autoComplete="name" required />
</Field>
<Field label="Email address">
<Input name="email" type="email" autoComplete="email" required />
</Field>
</StepperPanel>
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Workspace details</StepperHeading>
<Field label="Workspace name">
<Input name="workspace" type="text" required />
</Field>
<Field label="Team size">
<Select custom name="team-size">
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</Select>
</Field>
</StepperPanel>
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Review your workspace</StepperHeading>
<p>Check your details, then create the workspace.</p>
<div><Button color="primary" type="submit">Create workspace</Button></div>
</StepperPanel>
<StepperActions>
<StepperBack />
<StepperNext />
</StepperActions>
</Stepper>
<div><Button variant="outline" type="reset">Reset setup</Button></div>
</form>
);
}import {
Button, Field, Input, Select, Stepper, StepperActions, StepperBack, StepperContent, StepperHeading, StepperItem, StepperLabel,
StepperList, StepperMarker, StepperNext, StepperPanel, StepperProgress, StepperState, StepperStep,
} from '@pelatform/react/prefixed';
const steps = ['Account', 'Workspace', 'Review'];
export function Example() {
return (
<form className="plf:flex plf:flex-col plf:gap-4">
<Stepper>
<StepperList aria-label="Workspace setup steps">
{steps.map(label => (
<StepperItem key={label}>
<StepperStep>
<StepperMarker />
<StepperContent>
<StepperLabel>{label}</StepperLabel>
<StepperState />
</StepperContent>
</StepperStep>
</StepperItem>
))}
</StepperList>
<StepperProgress aria-label="Workspace setup position" />
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Account information</StepperHeading>
<Field label="Full name">
<Input name="full-name" type="text" autoComplete="name" required />
</Field>
<Field label="Email address">
<Input name="email" type="email" autoComplete="email" required />
</Field>
</StepperPanel>
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Workspace details</StepperHeading>
<Field label="Workspace name">
<Input name="workspace" type="text" required />
</Field>
<Field label="Team size">
<Select custom name="team-size">
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</Select>
</Field>
</StepperPanel>
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Review your workspace</StepperHeading>
<p>Check your details, then create the workspace.</p>
<div><Button color="primary" type="submit">Create workspace</Button></div>
</StepperPanel>
<StepperActions>
<StepperBack />
<StepperNext />
</StepperActions>
</Stepper>
<div><Button variant="outline" type="reset">Reset setup</Button></div>
</form>
);
}Validation
data-plf-validate makes Next check the step’s fields first and report the first invalid one; going back stays free.
<form class="flex flex-col gap-4">
<div class="stepper" data-plf-stepper data-plf-validate>
<ol class="stepper-list" aria-label="Workspace setup steps" role="list">
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Account</span>
<span class="stepper-state" data-plf-stepper-state-label>Current step</span>
</span>
</button>
</li>
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Workspace</span>
<span class="stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
<li class="stepper-item">
<button class="stepper-step" type="button">
<span class="stepper-marker"></span>
<span class="stepper-content">
<span class="stepper-label">Review</span>
<span class="stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
</ol>
<progress class="progress" value="1" max="3" aria-label="Workspace setup position">Step 1 of 3</progress>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Account information</h3>
<div class="field">
<label class="field-label" for="validation-name">Full name</label>
<input class="input" id="validation-name" name="full-name" type="text" autocomplete="name" required>
</div>
<div class="field">
<label class="field-label" for="validation-email">Email address</label>
<input class="input" id="validation-email" name="email" type="email" autocomplete="email" required>
</div>
</section>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Workspace details</h3>
<div class="field">
<label class="field-label" for="validation-workspace">Workspace name</label>
<input class="input" id="validation-workspace" name="workspace" type="text" required>
</div>
<div class="field">
<label class="field-label" for="validation-team-size">Team size</label>
<select class="select" id="validation-team-size" name="team-size" data-plf-select>
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</select>
</div>
</section>
<section class="stepper-panel flex flex-col gap-4">
<h3 class="stepper-heading" data-plf-stepper-focus>Review your workspace</h3>
<p>Check your details, then create the workspace.</p>
<div><button class="btn btn-primary" type="submit">Create workspace</button></div>
</section>
<div class="stepper-actions">
<button class="btn btn-outline stepper-back" type="button" data-plf-stepper-back hidden>Back</button>
<button class="btn btn-primary stepper-next" type="button" data-plf-stepper-next hidden>Next</button>
</div>
</div>
<div><button class="btn btn-outline" type="reset">Reset setup</button></div>
</form><form class="plf:flex plf:flex-col plf:gap-4">
<div class="plf:stepper" data-plf-stepper data-plf-validate>
<ol class="plf:stepper-list" aria-label="Workspace setup steps" role="list">
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Account</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Current step</span>
</span>
</button>
</li>
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Workspace</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
<li class="plf:stepper-item">
<button class="plf:stepper-step" type="button">
<span class="plf:stepper-marker"></span>
<span class="plf:stepper-content">
<span class="plf:stepper-label">Review</span>
<span class="plf:stepper-state" data-plf-stepper-state-label>Upcoming</span>
</span>
</button>
</li>
</ol>
<progress class="plf:progress" value="1" max="3" aria-label="Workspace setup position">Step 1 of 3</progress>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Account information</h3>
<div class="plf:field">
<label class="plf:field-label" for="validation-name">Full name</label>
<input class="plf:input" id="validation-name" name="full-name" type="text" autocomplete="name" required>
</div>
<div class="plf:field">
<label class="plf:field-label" for="validation-email">Email address</label>
<input class="plf:input" id="validation-email" name="email" type="email" autocomplete="email" required>
</div>
</section>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Workspace details</h3>
<div class="plf:field">
<label class="plf:field-label" for="validation-workspace">Workspace name</label>
<input class="plf:input" id="validation-workspace" name="workspace" type="text" required>
</div>
<div class="plf:field">
<label class="plf:field-label" for="validation-team-size">Team size</label>
<select class="plf:select" id="validation-team-size" name="team-size" data-plf-select>
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</select>
</div>
</section>
<section class="plf:stepper-panel plf:flex plf:flex-col plf:gap-4">
<h3 class="plf:stepper-heading" data-plf-stepper-focus>Review your workspace</h3>
<p>Check your details, then create the workspace.</p>
<div><button class="plf:btn plf:btn-primary" type="submit">Create workspace</button></div>
</section>
<div class="plf:stepper-actions">
<button class="plf:btn plf:btn-outline plf:stepper-back" type="button" data-plf-stepper-back hidden>Back</button>
<button class="plf:btn plf:btn-primary plf:stepper-next" type="button" data-plf-stepper-next hidden>Next</button>
</div>
</div>
<div><button class="plf:btn plf:btn-outline" type="reset">Reset setup</button></div>
</form>'use client';
import { useRef, useState } from 'react';
import {
Button, Field, Input, Select, Stepper, StepperActions, StepperBack, StepperContent, StepperHeading, StepperItem, StepperLabel,
StepperList, StepperMarker, StepperNext, StepperPanel, StepperProgress, StepperState, StepperStep,
} from '@pelatform/react';
const steps = ['Account', 'Workspace', 'Review'];
export function Example() {
const [step, setStep] = useState(0);
const stepper = useRef<HTMLDivElement>(null);
// Moving forward first reports the shown step's first invalid field; going back stays free.
function change(next: number) {
const panel = stepper.current?.querySelector(':scope > section:not([hidden])');
const fields = [...(panel?.querySelectorAll<HTMLInputElement>('input, select, textarea') ?? [])];
const invalid = next > step && fields.find(field => !field.validity.valid);
if (invalid) invalid.reportValidity();
else setStep(next);
}
return (
<form className="flex flex-col gap-4">
<Stepper ref={stepper} value={step} onValueChange={change}>
<StepperList aria-label="Workspace setup steps">
{steps.map(label => (
<StepperItem key={label}>
<StepperStep>
<StepperMarker />
<StepperContent>
<StepperLabel>{label}</StepperLabel>
<StepperState />
</StepperContent>
</StepperStep>
</StepperItem>
))}
</StepperList>
<StepperProgress aria-label="Workspace setup position" />
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Account information</StepperHeading>
<Field label="Full name">
<Input name="full-name" type="text" autoComplete="name" required />
</Field>
<Field label="Email address">
<Input name="email" type="email" autoComplete="email" required />
</Field>
</StepperPanel>
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Workspace details</StepperHeading>
<Field label="Workspace name">
<Input name="workspace" type="text" required />
</Field>
<Field label="Team size">
<Select custom name="team-size">
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</Select>
</Field>
</StepperPanel>
<StepperPanel className="flex flex-col gap-4">
<StepperHeading>Review your workspace</StepperHeading>
<p>Check your details, then create the workspace.</p>
<div><Button color="primary" type="submit">Create workspace</Button></div>
</StepperPanel>
<StepperActions>
<StepperBack />
<StepperNext />
</StepperActions>
</Stepper>
<div><Button variant="outline" type="reset">Reset setup</Button></div>
</form>
);
}'use client';
import { useRef, useState } from 'react';
import {
Button, Field, Input, Select, Stepper, StepperActions, StepperBack, StepperContent, StepperHeading, StepperItem, StepperLabel,
StepperList, StepperMarker, StepperNext, StepperPanel, StepperProgress, StepperState, StepperStep,
} from '@pelatform/react/prefixed';
const steps = ['Account', 'Workspace', 'Review'];
export function Example() {
const [step, setStep] = useState(0);
const stepper = useRef<HTMLDivElement>(null);
// Moving forward first reports the shown step's first invalid field; going back stays free.
function change(next: number) {
const panel = stepper.current?.querySelector(':scope > section:not([hidden])');
const fields = [...(panel?.querySelectorAll<HTMLInputElement>('input, select, textarea') ?? [])];
const invalid = next > step && fields.find(field => !field.validity.valid);
if (invalid) invalid.reportValidity();
else setStep(next);
}
return (
<form className="plf:flex plf:flex-col plf:gap-4">
<Stepper ref={stepper} value={step} onValueChange={change}>
<StepperList aria-label="Workspace setup steps">
{steps.map(label => (
<StepperItem key={label}>
<StepperStep>
<StepperMarker />
<StepperContent>
<StepperLabel>{label}</StepperLabel>
<StepperState />
</StepperContent>
</StepperStep>
</StepperItem>
))}
</StepperList>
<StepperProgress aria-label="Workspace setup position" />
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Account information</StepperHeading>
<Field label="Full name">
<Input name="full-name" type="text" autoComplete="name" required />
</Field>
<Field label="Email address">
<Input name="email" type="email" autoComplete="email" required />
</Field>
</StepperPanel>
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Workspace details</StepperHeading>
<Field label="Workspace name">
<Input name="workspace" type="text" required />
</Field>
<Field label="Team size">
<Select custom name="team-size">
<option value="small">1–5 people</option>
<option value="medium">6–20 people</option>
<option value="large">21+ people</option>
</Select>
</Field>
</StepperPanel>
<StepperPanel className="plf:flex plf:flex-col plf:gap-4">
<StepperHeading>Review your workspace</StepperHeading>
<p>Check your details, then create the workspace.</p>
<div><Button color="primary" type="submit">Create workspace</Button></div>
</StepperPanel>
<StepperActions>
<StepperBack />
<StepperNext />
</StepperActions>
</Stepper>
<div><Button variant="outline" type="reset">Reset setup</Button></div>
</form>
);
}JavaScript
Stepper needs JavaScript. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/button.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/progress.min.css">
<link rel="stylesheet" href="components/stepper.min.css">
<link rel="stylesheet" href="components/select.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/stepper.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/button.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/progress.prefixed.min.css">
<link rel="stylesheet" href="components/stepper.prefixed.min.css">
<link rel="stylesheet" href="components/select.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/stepper.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>| Attribute | Purpose |
|---|---|
data-plf-stepper |
Marks the container |
aria-controls |
On each step’s <button type="button"> in the stepper’s <ol>, its panel’s id; leave it off every step to show the stepper’s own <section>s in order, one per step. The <ol> is named with aria-label or aria-labelledby |
aria-current="step" |
The step shown first; otherwise the first enabled step |
disabled |
A step that cannot be entered; Back and Next stop before it |
data-plf-stepper-state-label |
Optional; filled with the step’s state |
data-plf-current-label, data-plf-complete-label, data-plf-upcoming-label, data-plf-disabled-label |
On the container, the state texts, as for another language; Current step, Completed, Upcoming and Unavailable by default |
data-plf-stepper-focus |
Optional; one per panel, focused after a move; otherwise the panel itself |
data-plf-stepper-back, data-plf-stepper-next |
Optional <button type="button"> controls, authored hidden |
<progress> |
Optional; one directly in the container, whose max, value and aria-valuetext the script sets |
data-plf-progress-label |
On the container, the progress text; {index} is the current step and {count} the number of steps, Step {index} of {count} by default |
data-plf-validate |
On the container: moving forward first checks the current step’s fields and reports the first invalid one, as the browser does on submit; going back stays free |
data-plf-stepper-step, data-plf-stepper-panel |
Optional; mark the steps and panels, which are otherwise the <ol>’s buttons and the stepper’s <section>s or their aria-controls targets |
People can return to any step they have reached; steps further ahead get aria-disabled="true".
Methods
| Method | Behavior |
|---|---|
PLF. |
Returns the instance, creating it for valid markup; options. names the panel to show first |
PLF. |
Returns the instance or null |
instance. |
Returns {panelId, index, total, furthestIndex}; indexes are zero-based |
instance., instance. |
Move one step |
instance. |
Shows the step of the panel with this id, which you write on a panel you select from code: a reached step or the step after the furthest one |
instance. |
Updates steps and buttons after you change disabled |
instance. |
Removes listeners and restores the markup, so every panel shows; values stay |
Methods move focus only with {focus: true}, and return false when the move is canceled, unchanged, disabled or out of reach.
Events
| Event | When |
|---|---|
plf: |
Before another step shows; cancelable, except with reason validation |
plf: |
After the new step shows |
Each event’s detail:
| Property | Value |
|---|---|
instance |
The Stepper instance |
previousPanelId |
The id of the panel shown before the move |
panelId |
The id of the panel the move goes to |
previousIndex |
The zero-based position of the step shown before the move |
index |
The zero-based position of the step the move goes to |
reason |
api, trigger or validation |
trigger |
The step, Back or Next button, the invalid field for validation, or null from a method |
A validation move shows the panel of an invalid field on native submit; resetting the form shows the first step again without events.
Keyboard
| Key | Action |
|---|---|
| Tab, Shift+Tab | Move between steps, the panel’s fields and the Back and Next buttons |
| Enter, Space | Activates the focused step or button |
React
Stepper from @pelatform/react renders this stepper: it keeps its own step, or the application sets it with value, and each part is a component of its own.
| Prop | Values | Default |
|---|---|---|
value |
The step shown, from 0, which the application changes in onValueChange; keeping it refuses the move, as the Validation example does |
Its own state |
defaultValue |
The step shown first when the application does not set value |
The first enabled step |
onValueChange |
(value), called when a step, Back, Next, an invalid field on submit or a form reset asks for another step |
None |
currentLabel, completeLabel, upcomingLabel, disabledLabel |
The state texts in StepperState |
Current step, Completed, Upcoming and Unavailable |
progressLabel |
(step, count), the progress text, with the step’s number from 1 |
Step {step} of {count} |
The parts:
| Part | Element |
|---|---|
StepperList |
An ol with stepper-list, named with aria-label |
StepperItem |
An li with stepper-item |
StepperStep |
A button with stepper-step, which shows its panel once reached; disabled keeps the step from being entered |
StepperMarker |
A span with stepper-marker |
StepperContent |
A span with stepper-content |
StepperLabel |
A span with stepper-label |
StepperState |
A span with stepper-state, holding the step’s state text |
StepperProgress |
A progress with progress, whose value is the step’s number |
StepperPanel |
A section with stepper-panel, one per step in order |
StepperHeading |
An h3 with stepper-heading, which takes the focus after a move; level sets 2 to 6 |
StepperActions |
A div with stepper-actions |
StepperBack, StepperNext |
A button with btn btn-outline stepper-back or btn btn-primary stepper-next, labeled Back or Next unless given children; color and variant give another look |
The other props are the element’s own, className and ref included.
| Variable | Default |
|---|---|
--plf-stepper-gap |
Space 4 (16px); Space 3 (12px) between steps |
--plf-stepper-color |
Text |
--plf-stepper-bg |
Transparent, on steps and panels |
--plf-stepper-border |
--plf-color-border-subtle; primary on the current step unless set |
--plf-stepper-radius |
Large radius (8px) |
--plf-stepper-marker-size |
2rem |
--plf-stepper-marker-bg, --plf-stepper-marker-color |
Muted; primary when current, primary subtle when completed |
--plf-stepper-panel-padding |
Space 4 (16px) |