Stepper
Guide a user through ordered tasks with progress and eligibility rules.
Usage
Checkout
Move through an ordered checkout flow one available step at a time.
Move through an ordered checkout flow one available step at a time.
Contact and sign-in details
Address and shipping method
Secure payment information
Confirm and place the order
<!-- Stepper / Checkout -->
<script setup lang="ts">
import { StepperRoot, StepperList, StepperStep, StepperContent, StepperPrevious, StepperNext } from '@sectile/vue/stepper'
import { ref } from 'vue'
const steps = [
{ id: 'account', label: 'Account', detail: 'Contact and sign-in details' },
{ id: 'delivery', label: 'Delivery', detail: 'Address and shipping method' },
{ id: 'payment', label: 'Payment', detail: 'Secure payment information' },
{ id: 'review', label: 'Review', detail: 'Confirm and place the order' },
]
const stepIDs = steps.map(({ id }) => id)
const current = ref('delivery')
const stepLabel = (id: string) => steps.find(step => step.id === id)?.label ?? id
</script>
<template>
<StepperRoot v-model="current" :items="stepIDs">
<StepperList>
<StepperStep v-for="(step, index) in steps" :key="step.id" :value="step.id">
{{ index + 1 }}. {{ step.label }}
</StepperStep>
</StepperList>
<StepperContent v-for="step in steps" :key="step.id" :value="step.id">
<strong>{{ step.label }}</strong>
<p>{{ step.detail }}</p>
<StepperPrevious>Back</StepperPrevious>
<StepperNext v-slot="{ targetValue }">
{{ targetValue === null ? 'Checkout steps complete' : 'Continue to ' + stepLabel(targetValue) }}
</StepperNext>
</StepperContent>
</StepperRoot>
</template>Controlled
Let the parent own the current value and apply accepted changes back to the component.
Let the parent own the current value and apply accepted changes back to the component.
Contact and sign-in details
Address and shipping method
Secure payment information
Confirm and place the order
<!-- Stepper / Controlled -->
<script setup lang="ts">
import { StepperRoot, StepperList, StepperStep, StepperContent, StepperPrevious, StepperNext } from '@sectile/vue/stepper'
import { ref } from 'vue'
const steps = [
{ id: 'account', label: 'Account', detail: 'Contact and sign-in details' },
{ id: 'delivery', label: 'Delivery', detail: 'Address and shipping method' },
{ id: 'payment', label: 'Payment', detail: 'Secure payment information' },
{ id: 'review', label: 'Review', detail: 'Confirm and place the order' },
]
const stepIDs = steps.map(({ id }) => id)
const current = ref('delivery')
const stepLabel = (id: string) => steps.find(step => step.id === id)?.label ?? id
</script>
<template>
<StepperRoot v-model="current" :items="stepIDs">
<StepperList>
<StepperStep v-for="(step, index) in steps" :key="step.id" :value="step.id">
{{ index + 1 }}. {{ step.label }}
</StepperStep>
</StepperList>
<StepperContent v-for="step in steps" :key="step.id" :value="step.id">
<strong>{{ step.label }}</strong>
<p>{{ step.detail }}</p>
<StepperPrevious>Back</StepperPrevious>
<StepperNext v-slot="{ targetValue }">
{{ targetValue === null ? 'Checkout steps complete' : 'Continue to ' + stepLabel(targetValue) }}
</StepperNext>
</StepperContent>
</StepperRoot>
</template>Examples
Gated step
Block forward movement until the current step satisfies its completion rule.
Block forward movement until the current step satisfies its completion rule.
Contact and sign-in details
Address and shipping method
Secure payment information
Confirm and place the order
<!-- Stepper / Gated Step -->
<script setup lang="ts">
import { StepperRoot, StepperList, StepperStep, StepperContent, StepperPrevious, StepperNext } from '@sectile/vue/stepper'
import { ref } from 'vue'
const steps = [
{ id: 'account', label: 'Account', detail: 'Contact and sign-in details' },
{ id: 'delivery', label: 'Delivery', detail: 'Address and shipping method' },
{ id: 'payment', label: 'Payment', detail: 'Secure payment information' },
{ id: 'review', label: 'Review', detail: 'Confirm and place the order' },
]
const stepIDs = steps.map(({ id }) => id)
const current = ref('delivery')
const stepLabel = (id: string) => steps.find(step => step.id === id)?.label ?? id
</script>
<template>
<StepperRoot v-model="current" :items="stepIDs">
<StepperList>
<StepperStep v-for="(step, index) in steps" :key="step.id" :value="step.id">
{{ index + 1 }}. {{ step.label }}
</StepperStep>
</StepperList>
<StepperContent v-for="step in steps" :key="step.id" :value="step.id">
<strong>{{ step.label }}</strong>
<p>{{ step.detail }}</p>
<StepperPrevious>Back</StepperPrevious>
<StepperNext v-slot="{ targetValue }">
{{ targetValue === null ? 'Checkout steps complete' : 'Continue to ' + stepLabel(targetValue) }}
</StepperNext>
</StepperContent>
</StepperRoot>
</template>API
Vue package: @sectile/vue/stepper
StepperRootStepperListStepperStepStepperContentStepperIndicatorStepperPreviousStepperNext
Props
StepperRootProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
defaultValueInitial value used when the component owns its state.
disabledWhether interaction is unavailable.
disabledItemsItem values excluded from focus and selection.
itemsOrdered item values managed by the component.
modelValueCurrent value when state is controlled by the parent.
orientationAxis used for layout and keyboard movement.
readonlyWhether the value can be inspected but not changed.
StepperActionProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
disabledWhether interaction is unavailable.
Slots
StepperActionSlotProps
disabledWhether interaction is unavailable.
targetValueValue the action will activate, or null when no enabled step remains in that direction.
valueCurrent value exposed by this contract.
Events
StepperRoot
activateEmitted when an item becomes active.
highlightEmitted when the highlighted item changes.
update:modelValueEmitted when the component requests a new controlled value.
Other types
StepperValueChangeHandler
type StepperValueChangeHandler = (value: string) => voidStepperHighlightHandler
type StepperHighlightHandler = (value: string | null) => voidStepperActivateHandler
type StepperActivateHandler = (value: string) => voidParts
Shared scope: [data-scope="stepper"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
list | [data-part="list"] | Groups the component items in navigation order. | — |
step | [data-part="step"] | Represents one ordered workflow step. | — |
indicator | [data-part="indicator"] | Shows state or position without replacing the primary content. | — |
content | [data-part="content"] | Contains the component content shown for the active state. | — |
previous | [data-part="previous"] | Activates and focuses the previous enabled step. | data-target-value="<value>"data-disabled="" |
next | [data-part="next"] | Activates and focuses the next enabled step. | data-target-value="<value>"data-disabled="" |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow Left / Arrow Right | Move between tabs in a horizontal list. |
| Arrow Up / Arrow Down | Move between tabs in a vertical list. |
| Home / End | Move to the first or last tab. |
| Enter / Space | Activate the focused tab in manual activation mode. |
Accessibility
The ordered step list exposes the current step and associates each step trigger with its content panel.
