Skip to content

Steps ​

A step indicator component for multi-step workflows. Supports horizontal and vertical layouts, icons, descriptions, error states, clickable navigation, multiple sizes, and full CSS customization.

Basic ​

Account
2
Profile
3
Review
4
Done
vue
<script setup>
import { ref } from 'vue'
import { VxSteps } from 'veloxui'

const current = ref(1)

const items = [
  { key: 'account', title: 'Account' },
  { key: 'profile', title: 'Profile' },
  { key: 'review', title: 'Review' },
  { key: 'done', title: 'Done' },
]
</script>

<template>
  <VxSteps :items="items" :current="current" />
</template>

With Descriptions ​

AccountCreate your account credentials
2
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
vue
<VxSteps :items="[
  { key: 'account', title: 'Account', description: 'Create your account credentials' },
  { key: 'profile', title: 'Profile', description: 'Fill in your personal details' },
  { key: 'review', title: 'Review', description: 'Verify all information' },
  { key: 'done', title: 'Done', description: 'Setup complete' },
]" :current="1" />

With Icons ​

Account
Settings
Upload
Complete
vue
<VxSteps :items="[
  { key: 'account', title: 'Account', icon: 'user' },
  { key: 'settings', title: 'Settings', icon: 'settings' },
  { key: 'upload', title: 'Upload', icon: 'upload' },
  { key: 'done', title: 'Complete', icon: 'check' },
]" :current="2" />

Error State ​

Set error: true on a step item to show it in an error state.

Account
Verification
3
Done
vue
<VxSteps :items="[
  { key: 'account', title: 'Account' },
  { key: 'verify', title: 'Verification', error: true },
  { key: 'done', title: 'Done' },
]" :current="1" />

Clickable ​

Set clickable to allow clicking on any step. Use v-model:current for two-way binding.

AccountCreate your account credentials
2
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
Current step: 1
vue
<VxSteps v-model:current="current" :items="items" clickable />

Vertical ​

Order PlacedYour order has been submitted
2
ProcessingWe are preparing your order
3
ShippedPackage is on its way
4
DeliveredPackage has arrived
vue
<script setup>
import { ref } from 'vue'
import { VxSteps } from 'veloxui'

const current = ref(1)

const items = [
  { key: 'order', title: 'Order Placed', description: 'Your order has been submitted' },
  { key: 'processing', title: 'Processing', description: 'We are preparing your order' },
  { key: 'shipped', title: 'Shipped', description: 'Package is on its way' },
  { key: 'delivered', title: 'Delivered', description: 'Package has arrived' },
]
</script>

<template>
  <VxSteps :items="items" :current="current" direction="vertical" />
</template>

Sizes ​

Three sizes: sm, md (default), and lg.

Account
Profile
3
Review
4
Done
Account
Profile
3
Review
4
Done
Account
Profile
3
Review
4
Done
vue
<VxSteps :items="items" :current="2" size="sm" />
<VxSteps :items="items" :current="2" size="md" />
<VxSteps :items="items" :current="2" size="lg" />

Square Variant ​

Use variant="square" for rounded-square indicators instead of circles.

AccountCreate your account credentials
2
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
AccountCreate your account credentials
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
vue
<VxSteps :items="items" :current="1" variant="square" clickable />
<VxSteps :items="items" :current="2" variant="square" direction="vertical" />

Custom Dot Size & Line Width ​

Use dot-size and line-width props to override the size preset values.

Account
2
Profile
3
Review
4
Done
Account
2
Profile
3
Review
4
Done
vue
<VxSteps :items="items" :current="1" :dot-size="40" :line-width="2" />
<VxSteps :items="items" :current="1" :dot-size="20" :line-width="2" />

Custom Colors (CSS Variables) ​

Override any visual aspect via CSS custom properties on a wrapper class.

AccountCreate your account credentials
2
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
AccountCreate your account credentials
ProfileFill in your personal details
3
ReviewVerify all information
4
DoneSetup complete
vue
<template>
  <div class="steps-green-theme">
    <VxSteps :items="items" :current="1" clickable />
  </div>
</template>

<style>
.steps-green-theme .vx-steps {
  --vx-steps-active-bg: #16a34a;
  --vx-steps-active-border: #16a34a;
  --vx-steps-active-color: #fff;
  --vx-steps-active-shadow: 0 0 0 3px rgba(22, 163, 74, 0.16);
  --vx-steps-completed-bg: #16a34a;
  --vx-steps-completed-border: #16a34a;
  --vx-steps-completed-color: #fff;
  --vx-steps-line-done-color: #16a34a;
}
</style>

Custom Slots ​

Use slots to fully customize titles, descriptions, icons, and add extra content per step.

Account Create your account credentials
2
Profile CurrentFill in your personal details
3
Review Verify all information
4
Done Setup complete
vue
<VxSteps :items="items" :current="current" clickable direction="vertical">
  <!-- Custom title for all steps -->
  <template #title="{ item, status }">
    <span :style="{ fontWeight: status === 'active' ? 700 : 400 }">
      {{ item.title }}
      <VxTag v-if="status === 'active'" size="sm">Current</VxTag>
    </span>
  </template>

  <!-- Extra content only for the 'review' step -->
  <template #content-review="{ status }">
    <div v-if="status === 'active'" style="padding: 12px; background: var(--muted); border-radius: 8px;">
      Please review all your information before proceeding.
    </div>
  </template>
</VxSteps>

Content Panel ​

Use panel-{key} slots to render step-specific content below the steps bar. The active step's panel is shown automatically.

1
Account
2
Profile
3
Confirm
Create your account
vue
<script setup>
import { ref } from 'vue'
import { VxSteps, VxInput, VxButton } from 'veloxui'

const current = ref(0)

const items = [
  { key: 'account', title: 'Account' },
  { key: 'profile', title: 'Profile' },
  { key: 'confirm', title: 'Confirm' },
]

function next() {
  if (current.value < items.length - 1) current.value++
}
function prev() {
  if (current.value > 0) current.value--
}
</script>

<template>
  <VxSteps :items="items" :current="current" clickable>
    <template #panel-account>
      <div style="padding: 20px; border: 1px solid var(--border); border-radius: 10px;">
        <VxInput placeholder="Email address" />
        <VxInput placeholder="Password" type="password" />
        <VxButton size="sm" @click="next">Next</VxButton>
      </div>
    </template>
    <template #panel-profile>
      <div style="padding: 20px; border: 1px solid var(--border); border-radius: 10px;">
        <VxInput placeholder="Full name" />
        <VxButton variant="outline" size="sm" @click="prev">Back</VxButton>
        <VxButton size="sm" @click="next">Next</VxButton>
      </div>
    </template>
    <template #panel-confirm>
      <div style="text-align: center;">All done!</div>
    </template>
  </VxSteps>
</template>

Vertical Content Panel ​

The content panel works with vertical direction too — it renders beside the steps.

1
InformationBasic details
2
AddressShipping address
3
PaymentPayment method
Basic Information
vue
<VxSteps :items="items" :current="current" direction="vertical" clickable>
  <template #panel-info>
    <!-- Your form content here -->
  </template>
  <template #panel-address>
    <!-- Address form -->
  </template>
  <template #panel-payment>
    <!-- Payment form -->
  </template>
</VxSteps>

Simple Wizard ​

A minimal wizard with just Next / Back buttons (no content panel).

1
Choose Plan
2
Billing
3
Confirm
vue
<script setup>
import { ref } from 'vue'
import { VxSteps, VxButton } from 'veloxui'

const current = ref(0)

const items = [
  { key: 'plan', title: 'Choose Plan' },
  { key: 'billing', title: 'Billing' },
  { key: 'confirm', title: 'Confirm' },
]

function next() {
  if (current.value < items.length - 1) current.value++
}
function prev() {
  if (current.value > 0) current.value--
}
</script>

<template>
  <VxSteps :items="items" :current="current" />
  <div style="margin-top: 20px; display: flex; gap: 8px; justify-content: flex-end;">
    <VxButton variant="outline" size="sm" :disabled="current === 0" @click="prev">Back</VxButton>
    <VxButton size="sm" @click="next" :disabled="current === items.length - 1">Next</VxButton>
  </div>
</template>

API ​

VxSteps Props ​

PropTypeDefaultDescription
itemsStepItem[][]Step items
currentnumber0Active step index (zero-based)
direction'horizontal' | 'vertical''horizontal'Layout direction
size'sm' | 'md' | 'lg''md'Step indicator size
variant'circle' | 'square''circle'Indicator shape
clickablebooleanfalseAllow clicking steps to navigate
dot-sizenumber | string—Override indicator size (e.g. 40 or '40px')
line-widthnumber | string—Override line thickness (e.g. 2 or '2px')
root-classstring | string[] | object—Class on root

StepItem ​

PropertyTypeRequiredDescription
keystringYesUnique identifier
titlestringYesStep title
descriptionstringNoStep description text
iconstring | ComponentNoCustom icon (replaces number)
disabledbooleanNoDisable this step
errorbooleanNoShow error state

Slots ​

SlotPropsDescription
icon{ item, status, index }Custom indicator for all steps
icon-{key}{ item, status, index }Custom indicator for a specific step
title{ item, status, index }Custom title for all steps
title-{key}{ item, status, index }Custom title for a specific step
description{ item, status, index }Custom description for all steps
description-{key}{ item, status, index }Custom description for a specific step
content-{key}{ item, status, index }Extra content area below a specific step's text
line{ index, status, done }Custom line connector between steps
panel{ item, status, index }Default content panel for all steps
panel-{key}{ item, status, index }Content panel for a specific step (shown when active)

Events ​

EventPayloadDescription
update:current(index: number)Step changed (clickable mode)
click(index, item)Step clicked

CSS Custom Properties ​

Override these on the .vx-steps element or a parent wrapper to customize colors, sizing, and spacing.

VariableDefaultDescription
--vx-steps-dot-sizeSize presetIndicator width/height
--vx-steps-dot-radius50% / 8pxIndicator border-radius
--vx-steps-dot-font-sizeSize presetNumber font-size in dot
--vx-steps-dot-font-weight600Number font-weight in dot
--vx-steps-dot-bgvar(--background)Upcoming dot background
--vx-steps-dot-bordervar(--border)Upcoming dot border
--vx-steps-dot-colorvar(--muted-foreground)Upcoming dot text color
--vx-steps-active-bgvar(--primary)Active dot background
--vx-steps-active-bordervar(--primary)Active dot border
--vx-steps-active-colorvar(--primary-foreground)Active dot text color
--vx-steps-active-shadowring glowActive dot box-shadow
--vx-steps-completed-bgvar(--primary)Completed dot background
--vx-steps-completed-bordervar(--primary)Completed dot border
--vx-steps-completed-colorvar(--primary-foreground)Completed dot text color
--vx-steps-error-bgvar(--background)Error dot background
--vx-steps-error-bordervar(--destructive)Error dot border
--vx-steps-error-colorvar(--destructive)Error dot text color
--vx-steps-line-colorvar(--border)Incomplete line color
--vx-steps-line-done-colorvar(--primary)Completed line color
--vx-steps-line-width1pxLine thickness
--vx-steps-title-sizeSize presetTitle font-size
--vx-steps-title-weight500Title font-weight
--vx-steps-title-colorvar(--foreground)Title color
--vx-steps-title-upcoming-colorvar(--muted-foreground)Upcoming title color
--vx-steps-title-error-colorvar(--destructive)Error title color
--vx-steps-desc-sizeSize presetDescription font-size
--vx-steps-desc-colorvar(--muted-foreground)Description color
--vx-steps-text-gap8pxGap between indicator and text (horizontal)
--vx-steps-line-gap24pxVertical spacing between steps
--vx-steps-panel-gap24pxGap between steps bar and content panel
--vx-steps-panel-padding0Content panel padding