Overview
Step provides a sequential navigation system for multi-step workflows. It extends single selection with navigation methods (first, last, next, prev, step) and supports both automatic and manual activation modes.
Sub-Components
- Step.Root: Renderless container that manages step state
- Step.Item: Individual step item
Usage
<script lang="ts" setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
</script>
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account">Account</Step.Item>
<Step.Item value="profile">Profile</Step.Item>
<Step.Item value="review">Review</Step.Item>
</Step.Root>
</template>
Step.Root
Props
namespace
string
default:"'v0:step'"
Namespace for dependency injection (must match StepItem namespace)
Disables the entire step instance
Auto-select non-disabled items on registration
mandatory
boolean | 'force'
default:"false"
Controls mandatory step behavior:
false (default): No mandatory step enforcement
true: Prevents deselecting the last selected item
'force': Automatically selects the first non-disabled item on registration
Model
Slot Props
Whether the step instance is disabled
Step forward or backward by a specific count
Toggle an item’s step state by ID
Attributes including aria-multiselectable: false
Step.Item
Props
Unique identifier (auto-generated if not provided)
Optional display label (passed through to slot, not used in registration)
Value associated with this item
Disables this specific item
namespace
string
default:"'v0:step'"
Namespace for dependency injection
Slot Props
Value associated with this item
Whether this item is currently selected
Whether this item is disabled
Toggle this item’s step state
Attributes including aria-selected, aria-disabled, data-selected, and data-disabled
Examples
Basic
With Navigation
With Disabled Steps
With Data Attributes
With Step Method
Mandatory Force
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
</script>
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account" v-slot="{ isSelected }">
<div :class="{ 'font-bold': isSelected }">
Account Setup
</div>
</Step.Item>
<Step.Item value="profile" v-slot="{ isSelected }">
<div :class="{ 'font-bold': isSelected }">
Profile Information
</div>
</Step.Item>
<Step.Item value="review" v-slot="{ isSelected }">
<div :class="{ 'font-bold': isSelected }">
Review & Submit
</div>
</Step.Item>
</Step.Root>
</template>
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
</script>
<template>
<Step.Root v-model="currentStep" v-slot="{ next, prev }">
<div>
<Step.Item value="account">Account</Step.Item>
<Step.Item value="profile">Profile</Step.Item>
<Step.Item value="review">Review</Step.Item>
</div>
<div>
<button @click="prev">Previous</button>
<button @click="next">Next</button>
</div>
</Step.Root>
</template>
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
const profileCompleted = ref(false)
</script>
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account" v-slot="{ isSelected, isDisabled }">
<div :class="{ 'font-bold': isSelected, 'opacity-50': isDisabled }">
Account Setup
</div>
</Step.Item>
<Step.Item value="profile" v-slot="{ isSelected, isDisabled }">
<div :class="{ 'font-bold': isSelected, 'opacity-50': isDisabled }">
Profile Information
</div>
</Step.Item>
<Step.Item
value="review"
:disabled="!profileCompleted"
v-slot="{ isSelected, isDisabled }"
>
<div :class="{ 'font-bold': isSelected, 'opacity-50': isDisabled }">
Review & Submit
</div>
</Step.Item>
</Step.Root>
</template>
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
</script>
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account" v-slot="{ attrs }">
<div
v-bind="attrs"
class="data-[selected]:font-bold data-[disabled]:opacity-50"
>
Account Setup
</div>
</Step.Item>
<Step.Item value="profile" v-slot="{ attrs }">
<div
v-bind="attrs"
class="data-[selected]:font-bold data-[disabled]:opacity-50"
>
Profile Information
</div>
</Step.Item>
<Step.Item value="review" v-slot="{ attrs }">
<div
v-bind="attrs"
class="data-[selected]:font-bold data-[disabled]:opacity-50"
>
Review & Submit
</div>
</Step.Item>
</Step.Root>
</template>
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref('account')
</script>
<template>
<Step.Root v-model="currentStep" v-slot="{ step }">
<div>
<Step.Item value="account">Step 1</Step.Item>
<Step.Item value="profile">Step 2</Step.Item>
<Step.Item value="billing">Step 3</Step.Item>
<Step.Item value="review">Step 4</Step.Item>
</div>
<div>
<!-- Go back 2 steps -->
<button @click="step(-2)">Back 2</button>
<!-- Go forward 2 steps -->
<button @click="step(2)">Forward 2</button>
</div>
</Step.Root>
</template>
<script setup>
import { ref } from 'vue'
import { Step } from '@vuetify/v0'
const currentStep = ref()
</script>
<template>
<!-- Automatically selects first step -->
<Step.Root v-model="currentStep" mandatory="force">
<Step.Item value="account">Account</Step.Item>
<Step.Item value="profile">Profile</Step.Item>
<Step.Item value="review">Review</Step.Item>
</Step.Root>
</template>
Accessibility
- Step.Root provides
aria-multiselectable="false" to indicate single selection
- Step.Item provides ARIA attributes for selection and disabled state
- Items expose
data-selected and data-disabled attributes for styling
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account" v-slot="{ attrs }">
<div v-bind="attrs">
Account Setup
</div>
</Step.Item>
</Step.Root>
</template>
SSR
Step is fully compatible with SSR as it is renderless by default:
<template>
<Step.Root v-model="currentStep">
<Step.Item value="account">Account</Step.Item>
<Step.Item value="profile">Profile</Step.Item>
<Step.Item value="review">Review</Step.Item>
</Step.Root>
</template>