Rendered from the shared Frontfriend stories with React Base, the same
preview Studio shows. Styling comes from your Design System; the code below
is native to Reka UI.
Installation
Complete project setup first. Your configuration
must select vue/reka and include your Design System ID.
pnpm exec frontfriend download stepper -f vue --primitive reka
Review dependencies reported by the downloader and keep your source
changes in version control.
Usage
<script setup lang="ts">
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import { StepperPanel } from "@/components/ui/stepper";
import { StepperContent } from "@/components/ui/stepper";
import { reactive } from "vue";
import * as UI from "@/components/ui/stepper";
const Component = UI.Stepper;
const args = reactive(
{
"defaultValue": 2,
"orientation": "horizontal",
"value": 2,
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" },
);
</script>
<template>
<Stepper v-model="args.value" :orientation="args.orientation"
><StepperNav
><StepperItem v-for="step in 3" :key="step" :step="step"
><StepperTrigger
><StepperIndicator>{{ step }}</StepperIndicator></StepperTrigger
><StepperSeparator v-if="step < 3" /></StepperItem></StepperNav
><StepperPanel
><StepperContent v-for="step in 3" :key="step" :value="step"
>Step {{ step }}</StepperContent
></StepperPanel
></Stepper
>
</template>
Examples
Default
<script setup lang="ts">
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import { StepperPanel } from "@/components/ui/stepper";
import { StepperContent } from "@/components/ui/stepper";
import * as UI from "@/components/ui/stepper";
const steps = [1, 2, 3, 4];
const Component = UI.Stepper;
const args = {
"defaultValue": 2,
"orientation": "horizontal",
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
</script>
<template>
<Stepper :default-value="2" class="w-[420px] space-y-8">
<StepperNav>
<StepperItem v-for="step in steps" :key="step" :step="step">
<StepperTrigger>
<StepperIndicator>{{ step }}</StepperIndicator>
</StepperTrigger>
<StepperSeparator v-if="steps.length > step" />
</StepperItem>
</StepperNav>
<StepperPanel class="text-sm">
<StepperContent
v-for="step in steps"
:key="step"
:value="step"
class="flex items-center justify-center"
>
Step {{ step }} content
</StepperContent>
</StepperPanel>
</Stepper>
</template>
States
<script setup lang="ts">
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import * as UI from "@/components/ui/stepper";
const Component = UI.Stepper;
const args = {
"defaultValue": 2,
"orientation": "horizontal",
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
</script>
<template>
<Stepper :default-value="2" class="w-[420px] space-y-8">
<StepperNav>
<StepperItem :step="1" completed>
<StepperTrigger><StepperIndicator>1</StepperIndicator></StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem :step="2">
<StepperTrigger><StepperIndicator>2</StepperIndicator></StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem :step="3" loading>
<StepperTrigger><StepperIndicator>3</StepperIndicator></StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem :step="4" disabled>
<StepperTrigger><StepperIndicator>4</StepperIndicator></StepperTrigger>
</StepperItem>
</StepperNav>
</Stepper>
</template>
Controlled
<script setup lang="ts">
import { ref } from "vue";
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import { StepperPanel } from "@/components/ui/stepper";
import { StepperContent } from "@/components/ui/stepper";
import { Button } from "@/components/ui/button";
import * as UI from "@/components/ui/stepper";
const steps = [1, 2, 3, 4];
const Component = UI.Stepper;
const args = {
"defaultValue": 2,
"orientation": "horizontal",
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
const currentStep = ref(2);
const prevStep = () => {
currentStep.value = Math.max(1, currentStep.value - 1);
};
const nextStep = () => {
currentStep.value = Math.min(steps.length, currentStep.value + 1);
};
</script>
<template>
<Stepper v-model="currentStep" class="w-[420px] space-y-8">
<StepperNav>
<StepperItem v-for="step in steps" :key="step" :step="step">
<StepperTrigger
><StepperIndicator>{{ step }}</StepperIndicator></StepperTrigger
>
<StepperSeparator v-if="steps.length > step" />
</StepperItem>
</StepperNav>
<StepperPanel class="text-sm">
<StepperContent
v-for="step in steps"
:key="step"
:value="step"
class="flex items-center justify-center"
>
Step {{ step }} content
</StepperContent>
</StepperPanel>
<div class="flex items-center justify-between gap-2.5">
<Button
variant="outline"
size="sm"
:disabled="currentStep === 1"
@click="prevStep"
>Previous</Button
>
<Button
variant="outline"
size="sm"
:disabled="currentStep === steps.length"
@click="nextStep"
>Next</Button
>
</div>
</Stepper>
</template>
Title & Description
<script setup lang="ts">
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperTitle } from "@/components/ui/stepper";
import { StepperDescription } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import * as UI from "@/components/ui/stepper";
const titledSteps = [
{ title: "User Details", description: "Create your account" },
{ title: "Payment Info", description: "Add billing information" },
{ title: "Auth OTP", description: "Verify your identity" },
{ title: "Preview Form", description: "Review and finish" },
];
const Component = UI.Stepper;
const args = {
"defaultValue": 2,
"orientation": "horizontal",
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
</script>
<template>
<Stepper :default-value="2" class="w-[560px] space-y-8">
<StepperNav>
<StepperItem
v-for="(step, index) in titledSteps"
:key="step.title"
:step="index + 1"
class="relative flex-1 items-start"
>
<StepperTrigger class="flex flex-col gap-2.5">
<StepperIndicator>{{ index + 1 }}</StepperIndicator>
<StepperTitle>{{ step.title }}</StepperTitle>
<StepperDescription>{{ step.description }}</StepperDescription>
</StepperTrigger>
<StepperSeparator
v-if="titledSteps.length > index + 1"
class="absolute left-[calc(50%+0.875rem)] right-[calc(-50%+0.875rem)] top-3 m-0 flex-none"
/>
</StepperItem>
</StepperNav>
</Stepper>
</template>
Vertical
<script setup lang="ts">
import { Stepper } from "@/components/ui/stepper";
import { StepperNav } from "@/components/ui/stepper";
import { StepperItem } from "@/components/ui/stepper";
import { StepperTrigger } from "@/components/ui/stepper";
import { StepperIndicator } from "@/components/ui/stepper";
import { StepperTitle } from "@/components/ui/stepper";
import { StepperDescription } from "@/components/ui/stepper";
import { StepperSeparator } from "@/components/ui/stepper";
import * as UI from "@/components/ui/stepper";
const titledSteps = [
{ title: "User Details", description: "Create your account" },
{ title: "Payment Info", description: "Add billing information" },
{ title: "Auth OTP", description: "Verify your identity" },
{ title: "Preview Form", description: "Review and finish" },
];
const Component = UI.Stepper;
const args = {
"defaultValue": 2,
"orientation": "horizontal",
} satisfies Partial<
InstanceType<typeof Component> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & { orientation?: "horizontal" | "vertical" };
</script>
<template>
<Stepper
:default-value="2"
orientation="vertical"
class="w-[420px] space-y-8"
>
<StepperNav>
<StepperItem
v-for="(step, index) in titledSteps"
:key="step.title"
:step="index + 1"
class="relative items-start not-last:flex-1"
>
<StepperTrigger class="items-start gap-2.5 pb-12 last:pb-0">
<StepperIndicator>{{ index + 1 }}</StepperIndicator>
<div class="mt-0.5 grid gap-1 text-left">
<StepperTitle>{{ step.title }}</StepperTitle>
<StepperDescription>{{ step.description }}</StepperDescription>
</div>
</StepperTrigger>
<StepperSeparator
v-if="titledSteps.length > index + 1"
class="absolute inset-y-0 left-3 top-7 -order-1 m-0 -translate-x-1/2 group-data-[orientation=vertical]/stepper-nav:h-[calc(100%-2rem)]"
/>
</StepperItem>
</StepperNav>
</Stepper>
</template>
API reference
Frontfriend-owned props. Native HTML and inherited primitive props
remain documented by Reka UI.
Stepper
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
defaultValue | number | — | |
modelValue | number | — | |
orientation | StepperOrientation | — | |
StepperContent
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
forceMount | boolean | — | |
value | number | — | |
StepperDescription
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperIndicator
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperItem
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
completed | boolean | — | |
disabled | boolean | — | |
loading | boolean | — | |
step | number | — | |
StepperNav
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperPanel
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperSeparator
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperTitle
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
StepperTrigger
| Prop | Type | Default | Description |
asChild | boolean | — | |
class | HTMLAttributes["class"] | — | |
Configuration determines the actual classes and available styling hooks.
See Theming & component configuration before introducing
a repeated local override.