Skip to content

๐Ÿชœย ย Steps

Submitted by Arnaud Miribel

Summary

Progress-steps indicator for multi-step workflows, with vertical/horizontal orientation and numbered or dotted styles.

Functions

steps

Display a progress-steps indicator and return a :class:StepsState.

Renders a visual steps (progress indicator) and returns a :class:StepsState object. Index it to get context managers for each step, or call its navigation methods (.next(), .previous(), .set(n), .reset()) to change the active step and rerun.

Inspired by Base Web ProgressSteps <https://baseweb.design/components/progress-steps/>_.

Parameters:

Name Type Description Default
labels Sequence[str]

Step titles (one per step).

required
current int

Initial/default step index (zero-based). Once the user navigates via the returned object's methods, the internally persisted value takes precedence.

0
icons Sequence[str | int] | None

Optional sequence of icons for each step. Accepts integers (displayed as numbers), emoji strings, or Material Symbols in ":material/icon_name:" format. When None (default), dots are shown with a checkmark for completed steps.

None
horizontal bool

If True, lay out steps horizontally. Defaults to False (vertical).

False
height int | None

Component height in pixels. Defaults to an auto-computed value based on the number of steps and orientation.

None
width Literal['stretch', 'content']

"stretch" (default) fills the container. "content" sizes to fit the content.

'stretch'
key str | None

Unique key for this component instance. Required when using navigation methods (.next(), etc.) or when placing multiple steps components.

None

Returns:

Name Type Description
A StepsState

class:StepsState object. Use steps[i] as a context

StepsState

manager to place content for step i. Call steps.next(),

StepsState

steps.previous(), steps.set(n), or steps.reset()

StepsState

to navigate.

Example

s = steps(["Step 1", "Step 2"], key="s") with s[0]: ... if st.button("Next"): ... s.next() with s[1]: ... st.write("Done!")

Source code in src/streamlit_extras/steps/__init__.py
@extra
def steps(
    labels: Sequence[str],
    *,
    current: int = 0,
    icons: Sequence[str | int] | None = None,
    horizontal: bool = False,
    height: int | None = None,
    width: Literal["stretch", "content"] = "stretch",
    key: str | None = None,
) -> StepsState:
    """Display a progress-steps indicator and return a :class:`StepsState`.

    Renders a visual steps (progress indicator) and returns a
    :class:`StepsState` object. Index it to get context managers for
    each step, or call its navigation methods (``.next()``,
    ``.previous()``, ``.set(n)``, ``.reset()``) to change the active
    step and rerun.

    Inspired by `Base Web ProgressSteps <https://baseweb.design/components/progress-steps/>`_.

    Args:
        labels: Step titles (one per step).
        current: Initial/default step index (zero-based). Once the user
            navigates via the returned object's methods, the internally
            persisted value takes precedence.
        icons: Optional sequence of icons for each step. Accepts
            integers (displayed as numbers), emoji strings, or
            Material Symbols in ``":material/icon_name:"`` format.
            When ``None`` (default), dots are shown with a checkmark
            for completed steps.
        horizontal: If ``True``, lay out steps horizontally.
            Defaults to ``False`` (vertical).
        height: Component height in pixels. Defaults to an auto-computed
            value based on the number of steps and orientation.
        width: ``"stretch"`` (default) fills the container. ``"content"``
            sizes to fit the content.
        key: Unique key for this component instance. Required when using
            navigation methods (``.next()``, etc.) or when placing
            multiple steps components.

    Returns:
        A :class:`StepsState` object. Use ``steps[i]`` as a context
        manager to place content for step *i*. Call ``steps.next()``,
        ``steps.previous()``, ``steps.set(n)``, or ``steps.reset()``
        to navigate.

    Example:
        >>> s = steps(["Step 1", "Step 2"], key="s")
        >>> with s[0]:
        ...     if st.button("Next"):
        ...         s.next()
        >>> with s[1]:
        ...     st.write("Done!")
    """
    session_key = _STATE_KEY_PREFIX + (key or "default")

    if session_key in st.session_state:
        active = st.session_state[session_key]
    else:
        active = current
        st.session_state[session_key] = active

    active = max(0, min(active, len(labels) - 1))

    computed_height = (64 if horizontal else 8 + 48 * len(labels)) if height is None else height

    _STEPS_COMPONENT(
        data={
            "labels": list(labels),
            "current": active,
            "horizontal": horizontal,
            "icons": [str(i) for i in icons] if icons is not None else None,
        },
        key=key,
        height=computed_height,
        width=width,
    )

    return StepsState(
        n_steps=len(labels),
        current=active,
        session_key=session_key,
    )

Import:

from streamlit_extras.steps import steps # (1)!
  1. You should add this to the top of your .py file ๐Ÿ› 

Examples

example_vertical_numbered

def example_vertical_numbered() -> None:

    left, right = st.columns((1, 3))

    with left:
        s = steps(
            ["Account Setup", "Preferences", "Confirmation"],
            icons=range(1, 4),
            key="demo_vn",
        )

    with right:
        with s[0]:
            st.text_input("Your name", key="name_input")
            if st.button("Next", key="vn_next_0"):
                s.next()

        with s[1]:
            st.selectbox("Theme", ["Light", "Dark"], key="theme_select")
            with st.container(horizontal=True):
                if st.button("Back", key="vn_back_1"):
                    s.previous()
                if st.button("Next", key="vn_next_1"):
                    s.next()

        with s[2]:
            st.success("All done! You're all set.")
            if st.button("Reset", key="vn_reset"):
                s.reset()

example_horizontal_numbered

def example_horizontal_numbered() -> None:
    h_steps = steps(
        ["Upload", "Review", "Submit"],
        horizontal=True,
        icons=range(1, 4),
        key="demo_hn",
    )

    with h_steps[0]:
        st.info("Upload your files here.")
        if st.button("Next", key="hn_next_0"):
            h_steps.next()

    with h_steps[1]:
        st.info("Review your submission.")
        c1, c2 = st.columns(2)
        with c1:
            if st.button("Back", key="hn_back_1"):
                h_steps.previous()
        with c2:
            if st.button("Next", key="hn_next_1"):
                h_steps.next()

    with h_steps[2]:
        st.info("Click submit to finish.")
        if st.button("Start over", key="hn_reset"):
            h_steps.reset()

example_vertical_dots

def example_vertical_dots() -> None:
    s = steps(
        ["Connect", "Configure", "Deploy", "Monitor"],
        key="demo_vd",
    )

    with s[0]:
        st.write("Connect to your data source.")
        if st.button("Next", key="vd_next_0"):
            s.next()

    with s[1]:
        st.write("Set up your pipeline configuration.")
        if st.button("Next", key="vd_next_1"):
            s.next()

    with s[2]:
        st.write("Deploy to production.")
        if st.button("Next", key="vd_next_2"):
            s.next()

    with s[3]:
        st.write("Monitor your deployment.")
        if st.button("Reset", key="vd_reset"):
            s.reset()

example_material_icons

def example_material_icons() -> None:
    _labels = ["Cart", "Shipping", "Payment", "Done"]
    h_steps = steps(
        _labels,
        horizontal=True,
        icons=[
            ":material/shopping_cart:",
            ":material/local_shipping:",
            ":material/payment:",
            ":material/check_circle:",
        ],
        key="demo_hd",
    )

    with h_steps[0]:
        st.write("Review your cart items.")
        if st.button("Next", key="hd_next_0"):
            h_steps.next()

    with h_steps[1]:
        st.write("Enter shipping details.")
        if st.button("Next", key="hd_next_1"):
            h_steps.next()

    with h_steps[2]:
        st.write("Complete payment.")
        if st.button("Next", key="hd_next_2"):
            h_steps.next()

    with h_steps[3]:
        st.balloons()
        st.success("Order placed!")
        if st.button("New order", key="hd_reset"):
            h_steps.reset()

example_emoji_icons

def example_emoji_icons() -> None:
    s = steps(
        ["Idea", "Build", "Test", "Ship"],
        icons=["๐Ÿ’ก", "๐Ÿ”จ", "๐Ÿงช", "๐Ÿš€"],
        key="demo_emoji",
    )

    with s[0]:
        st.write("Brainstorm your idea.")
        if st.button("Next", key="em_next_0"):
            s.next()

    with s[1]:
        st.write("Build the prototype.")
        if st.button("Next", key="em_next_1"):
            s.next()

    with s[2]:
        st.write("Run your tests.")
        if st.button("Next", key="em_next_2"):
            s.next()

    with s[3]:
        st.success("Shipped!")
        if st.button("Start over", key="em_reset"):
            s.reset()

example_jump_to_step

def example_jump_to_step() -> None:
    s = steps(
        ["Intro", "Details", "Review", "Submit"],
        icons=range(1, 5),
        key="demo_jump",
    )

    with s[0]:
        st.write("Welcome! Jump to any step:")
        c1, c2, c3 = st.columns(3)
        with c1:
            if st.button("Go to Details", key="j_1"):
                s.set(1)
        with c2:
            if st.button("Go to Review", key="j_2"):
                s.set(2)
        with c3:
            if st.button("Go to Submit", key="j_3"):
                s.set(3)

    with s[1]:
        st.write("Fill in your details.")
        if st.button("Back", key="j_back_1"):
            s.previous()

    with s[2]:
        st.write("Review everything.")
        if st.button("Back", key="j_back_2"):
            s.previous()

    with s[3]:
        st.write("Ready to submit!")
        if st.button("Reset", key="j_reset"):
            s.reset()