Skip to content

Stepper

Stepper and StepperStep show progress through a multi-step flow such as onboarding, checkout, setup, or account verification.

Stepper is display-only by default. It does not manage state for you; your route or application state decides which step is current.

Import

from faststrap import Stepper, StepperStep

Basic Usage

Stepper(
    StepperStep("Account", status="complete"),
    StepperStep("Profile", status="current"),
    StepperStep("Billing", status="pending"),
)

Numbered Steps

Stepper(
    StepperStep("Account", step=1, status="complete"),
    StepperStep("Profile", step=2, status="current"),
    StepperStep("Billing", step=3),
)

Vertical Stepper

Stepper(
    StepperStep("Account", description="Create your workspace", status="complete"),
    StepperStep("Profile", description="Add your team details", status="current"),
    StepperStep("Billing", description="Choose a plan"),
    orientation="vertical",
)

Clickable Steps

Stepper(
    StepperStep("Account", status="complete", href="/setup/account"),
    StepperStep("Profile", status="current", href="/setup/profile"),
    StepperStep("Billing", href="/setup/billing"),
)

Parameters

Component Param Type Description
Stepper *steps Any StepperStep children or strings.
Stepper orientation horizontal | vertical Layout direction.
Stepper numbered bool Adds numbers when string steps are passed.
StepperStep title str Step label.
StepperStep description str | None Optional helper text.
StepperStep status complete | current | pending | error Step state.
StepperStep step int | str | None Marker content.
StepperStep icon str | None Bootstrap icon override.
StepperStep href str | None Optional link target.

faststrap.components.display.stepper.Stepper(*steps, orientation='horizontal', numbered=True, **kwargs)

Render a progress stepper for onboarding, setup, or checkout flows.

Source code in src/faststrap/components/display/stepper.py
@register(category="display")
@beta
def Stepper(
    *steps: Any,
    orientation: StepperOrientation = "horizontal",
    numbered: bool = True,
    **kwargs: Any,
) -> Div:
    """Render a progress stepper for onboarding, setup, or checkout flows."""
    user_cls = kwargs.pop("cls", "")
    direction_cls = "flex-column" if orientation == "vertical" else "flex-column flex-md-row"
    attrs: dict[str, Any] = {
        "cls": merge_classes(
            "faststrap-stepper d-flex gap-3",
            direction_cls,
            user_cls,
        ),
        "role": "list",
        "data_fs_stepper": "true",
        "data_orientation": orientation,
    }
    attrs.update(convert_attrs(kwargs))

    rendered_steps = []
    for index, step_item in enumerate(steps, start=1):
        if isinstance(step_item, str):
            step_item = StepperStep(step_item, step=index if numbered else None)
        rendered_steps.append(Div(step_item, role="listitem", cls="flex-grow-1"))

    return Div(*rendered_steps, **attrs)

faststrap.components.display.stepper.StepperStep(title, *, description=None, status='pending', step=None, icon=None, href=None, **kwargs)

Render a single step for Stepper.

Source code in src/faststrap/components/display/stepper.py
@register(category="display")
@beta
def StepperStep(
    title: str,
    *,
    description: str | None = None,
    status: StepStatus = "pending",
    step: int | str | None = None,
    icon: str | None = None,
    href: str | None = None,
    **kwargs: Any,
) -> Div:
    """Render a single step for Stepper."""
    user_cls = kwargs.pop("cls", "")
    variant = STEP_VARIANTS.get(status, "secondary")
    attrs: dict[str, Any] = {
        "cls": merge_classes(
            "faststrap-stepper-step d-flex align-items-start gap-2 flex-grow-1",
            f"is-{status}",
            user_cls,
        ),
        "data_status": status,
        "aria_current": "step" if status == "current" else None,
    }
    attrs.update(convert_attrs(kwargs))

    marker_content: Any = step
    if icon:
        marker_content = Icon(icon, aria_hidden="true")
    elif status == "complete":
        marker_content = Icon("check", aria_hidden="true")
    elif step is None:
        marker_content = ""

    marker = Span(
        marker_content,
        cls=(
            "faststrap-stepper-marker rounded-circle d-inline-flex "
            f"align-items-center justify-content-center text-bg-{variant} fw-semibold"
        ),
        style={"width": "2rem", "height": "2rem", "min-width": "2rem"},
        aria_hidden="true",
    )
    label = Div(
        Span(title, cls="fw-semibold d-block"),
        Span(description, cls="small text-muted") if description else "",
        cls="min-w-0",
    )
    content = Div(marker, label, cls="d-flex align-items-start gap-2")
    if href:
        content = A(content, href=href, cls="text-decoration-none text-reset")

    return Div(content, **attrs)