The DevExtreme Stepper allows you to indicate progress within a multi-step process and allows users to navigate between individual steps. Use our Stepper UI component to implement multi-page navigation in lengthy forms such as store/cart checkout.
To get started with DevExtreme Stepper, refer to the following step-by-step tutorial: Getting Started with Stepper.
The following settings are available to you:
orientation (default: horizontal)
Stepper orientation (horizontal or vertical).
linear (default: true)
Specifies whether users must navigate the Stepper sequentially or can skip steps.
selectOnFocus (default: true)
Specifies whether steps focused with keyboard navigation are selected automatically.
rtlEnabled (default: false)
Switches the Stepper to Right-to-Left mode.
To add steps, populate the items collection or specify a dataSource.
Use the following properties to customize steps:
text
Indicator text. If you do not define this option, Stepper numbers steps sequentially.
icon
Indicator icon. Stepper prioritizes icons over the text property.
label
Step caption displayed next to the indicator.
optional
Adds an (Optional) label to the step.
isValid
Allows you to indicate step-related validation errors.
disabled
Deactivates the step.
hint
Tooltip text for the step.
template
Allows you to customize step-related appearance. This property overrides all other step settings.
@{
var steps = new dynamic[] {
new { text = "A", label = "Cart", icon = "cart" },
new { text = "B", label = "Shipping Info", icon = "clipboardtasklist" },
new { text = "C", label = "Promo Code", icon = "gift", optional = true },
new { text = "D", label = "Checkout", icon = "packagebox" },
new { text = "E", label = "Ordered", icon = "checkmarkcircle" }
};
var orientations = new dynamic[]
{
new { text = "Horizontal", value = "horizontal" },
new { text = "Vertical", value = "vertical" }
};
var navigationModes = new dynamic[]
{
new { text = "Non-linear", value = false },
new { text = "Linear", value = true }
};
}
<div class="stepper-demo">
<div class="widget-container">
<div class="widget-wrapper widget-wrapper-horizontal">
<div class="stepper-wrapper">
<div id="iconsLabel" class="stepper-label">Icons and Labels</div>
@(Html.DevExtreme().Stepper()
.ID("icons")
.ElementAttr("aria-labelledby", "iconsLabel")
.SelectedIndex(2)
.Linear(false)
.Items(items =>
{
items.Add()
.Icon(steps[0].icon)
.Label(steps[0].label)
.Text(steps[0].text);
items.Add()
.Icon(steps[1].icon)
.Label(steps[1].label)
.Text(steps[1].text);
items.Add()
.Icon(steps[2].icon)
.Label(steps[2].label)
.Text(steps[2].text)
.Optional(steps[2].optional);
items.Add()
.Icon(steps[3].icon)
.Label(steps[3].label)
.Text(steps[3].text);
items.Add()
.Icon(steps[4].icon)
.Label(steps[4].label)
.Text(steps[4].text);
})
)
</div>
<div class="stepper-wrapper">
<div id="numbersLabel" class="stepper-label">Numbers and Labels</div>
@(Html.DevExtreme().Stepper()
.ID("numbers")
.ElementAttr("aria-labelledby", "numbersLabel")
.SelectedIndex(2)
.Linear(false)
.Items(items =>
{
items.Add()
.Label(steps[0].label);
items.Add()
.Label(steps[1].label);
items.Add()
.Label(steps[2].label)
.Optional(steps[2].optional);
items.Add()
.Label(steps[3].label);
items.Add()
.Label(steps[4].label);
})
)
</div>
<div class="stepper-wrapper">
<div id="customTextLabel" class="stepper-label">Custom Text</div>
@(Html.DevExtreme().Stepper()
.ID("customText")
.ElementAttr("aria-labelledby", "customTextLabel")
.SelectedIndex(2)
.Linear(false)
.Items(items =>
{
items.Add().Text(steps[0].text);
items.Add().Text(steps[1].text);
items.Add().Text(steps[2].text);
items.Add().Text(steps[3].text);
items.Add().Text(steps[4].text);
})
)
</div>
</div>
</div>
<div class="options">
<div class="caption">Options</div>
<div class="option">
<div>Orientation</div>
@(Html.DevExtreme().ButtonGroup()
.ID("orientation")
.KeyExpr("value")
.Items(items =>
{
for (int i = 0; i < orientations.Length; i++)
{
items.Add()
.Text(orientations[i].text)
.Option("value", orientations[i].value);
}
})
.SelectedItemKeys(new[] { orientations[0].value })
.OnItemClick("buttonGroup_orientation_itemClick")
)
</div>
<div class="option">
<div>Navigation Mode</div>
@(Html.DevExtreme().ButtonGroup()
.ID("navigationMode")
.KeyExpr("value")
.Items(items =>
{
for (int i = 0; i < navigationModes.Length; i++)
{
items.Add()
.Text(navigationModes[i].text)
.Option("value", navigationModes[i].value);
}
})
.SelectedItemKeys(new[] { navigationModes[0].value })
.OnItemClick("buttonGroup_navigationMode_itemClick")
)
</div>
<div class="option-separator"></div>
<div class="option">
@(Html.DevExtreme().CheckBox()
.ID("selectOnFocus")
.Text("Select step on focus")
.Value(true)
.OnValueChanged("checkBox_selectOnFocus_valueChanged")
)
</div>
<div class="option">
@(Html.DevExtreme().CheckBox()
.ID("rtlMode")
.Text("Right-to-left mode")
.Value(false)
.OnValueChanged("checkBox_rtlMode_valueChanged")
)
</div>
</div>
</div>
<script>
const steppersIdsArray = ["#icons", "#numbers", "#customText"];
function buttonGroup_orientation_itemClick(data) {
const $widgetWrapper = $('.widget-wrapper');
const { text, value } = data.itemData;
const isVertical = text === 'Vertical';
$widgetWrapper.toggleClass('widget-wrapper-vertical', isVertical);
$widgetWrapper.toggleClass('widget-wrapper-horizontal', !isVertical);
steppersIdsArray.forEach(id => {
$(id).dxStepper("instance").option("orientation", data.itemData.value);
});
}
function buttonGroup_navigationMode_itemClick(data) {
steppersIdsArray.forEach(id => {
$(id).dxStepper("instance").option("linear", data.itemData.value);
});
}
function checkBox_selectOnFocus_valueChanged(data) {
steppersIdsArray.forEach(id => {
$(id).dxStepper("instance").option("selectOnFocus", data.value);
});
}
function checkBox_rtlMode_valueChanged(data) {
steppersIdsArray.forEach(id => {
$(id).dxStepper("instance").option("rtlEnabled", data.value);
});
}
</script>
using System.Web.Mvc;
using DevExtreme.MVC.Demos.Models.SampleData;
using DevExtreme.MVC.Demos.ViewModels;
namespace DevExtreme.MVC.Demos.Controllers {
public class StepperController : Controller {
public ActionResult Overview() {
return View();
}
}
}
.demo-container {
display: flex;
flex-direction: column;
}
.stepper-demo {
display: flex;
height: 580px;
gap: 20px;
}
.widget-container {
display: flex;
align-items: center;
justify-content: center;
width: calc(100% - 280px);
min-width: 320px;
overflow: clip;
}
.widget-wrapper {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
row-gap: 80px;
width: 100%;
}
.widget-wrapper-vertical {
display: flex;
flex-direction: row;
justify-content: space-around;
}
.widget-wrapper-vertical .stepper-wrapper {
width: auto;
max-width: 33%;
}
.widget-wrapper-vertical .stepper-label {
text-align: center;
white-space: nowrap;
}
.widget-wrapper-vertical #customText {
width: auto;
}
.dx-stepper-vertical {
height: 400px;
width: 100%;
}
.stepper-wrapper {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.stepper-label {
font-weight: 600;
}
.options {
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 300px;
box-sizing: border-box;
padding: 20px;
background-color: rgba(191, 191, 191, 0.15);
gap: 16px;
}
.caption {
font-weight: 500;
font-size: 18px;
}
.option {
display: flex;
flex-direction: column;
row-gap: 4px;
}
.option-separator {
border-bottom: 1px solid var(--dx-color-border);
}
.dx-buttongroup .dx-button {
width: 50%;
}