Stepper ▸ Overview

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.

Component Configuration

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.

Step Settings

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.

Icons and Labels
Numbers and Labels
Custom Text
Options
Orientation
Navigation Mode
@{
    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%;
}