Skip to content

Timeline

Timeline and TimelineItem render chronological events such as activity feeds, audit logs, booking progress, release history, and customer support notes.

Use TimelineItem for each event, then wrap the items in Timeline.

Import

from faststrap import Timeline, TimelineItem

Basic Usage

Timeline(
    TimelineItem(
        "Account created",
        description="Ada created the workspace.",
        time="09:15",
        icon="person-plus",
        variant="success",
    ),
    TimelineItem(
        "Invite sent",
        description="Grace was invited as an admin.",
        time="09:32",
        icon="send",
        variant="primary",
    ),
)

Compact Activity Feed

Timeline(
    TimelineItem("Deployment started", time="10:00", icon="rocket"),
    TimelineItem("Health checks passed", time="10:03", icon="check-circle", variant="success"),
    TimelineItem("Release completed", time="10:05", icon="flag", variant="success"),
    density="compact",
)

With Custom Metadata

TimelineItem(
    "Payment failed",
    description="The customer's card was declined.",
    time="Today",
    icon="credit-card",
    variant="danger",
    meta=StatusBadge("Needs attention", status="error"),
)

Parameters

Component Param Type Description
Timeline *items Any TimelineItem children or custom timeline rows.
Timeline density comfortable | compact Controls vertical spacing.
TimelineItem title str Main event title.
TimelineItem description Any | None Supporting event text or content.
TimelineItem time str | None Timestamp or relative time.
TimelineItem icon str | None Bootstrap icon name.
TimelineItem variant str Bootstrap marker variant.
TimelineItem meta Any | None Optional extra content such as badges or links.

faststrap.components.display.timeline.Timeline(*items, density='comfortable', **kwargs)

Render a vertical timeline of events.

Source code in src/faststrap/components/display/timeline.py
@register(category="display")
@beta
def Timeline(
    *items: Any,
    density: TimelineDensity = "comfortable",
    **kwargs: Any,
) -> Div:
    """Render a vertical timeline of events."""
    user_cls = kwargs.pop("cls", "")
    spacing_cls = "gap-3" if density == "compact" else "gap-4"
    attrs: dict[str, Any] = {
        "cls": merge_classes(
            "faststrap-timeline d-flex flex-column position-relative",
            spacing_cls,
            user_cls,
        ),
        "data_fs_timeline": "true",
    }
    attrs.update(convert_attrs(kwargs))
    return Div(*items, **attrs)

faststrap.components.display.timeline.TimelineItem(title, *, description=None, time=None, icon=None, variant='primary', active=False, meta=None, **kwargs)

Render one event in a timeline.

Source code in src/faststrap/components/display/timeline.py
@register(category="display")
@beta
def TimelineItem(
    title: str,
    *,
    description: Any | None = None,
    time: str | None = None,
    icon: str | None = None,
    variant: str = "primary",
    active: bool = False,
    meta: Any | None = None,
    **kwargs: Any,
) -> Div:
    """Render one event in a timeline."""
    user_cls = kwargs.pop("cls", "")
    attrs: dict[str, Any] = {
        "cls": merge_classes("faststrap-timeline-item position-relative d-flex gap-3", user_cls),
        "data_fs_timeline_item": "true",
    }
    attrs.update(convert_attrs(kwargs))

    marker_cls = merge_classes(
        "faststrap-timeline-marker rounded-circle d-inline-flex align-items-center justify-content-center",
        f"text-bg-{variant}",
        "shadow-sm" if active else "",
    )
    marker = Span(
        Icon(icon, aria_hidden="true") if icon else "",
        cls=marker_cls,
        style={"width": "2rem", "height": "2rem", "min-width": "2rem"},
        aria_hidden="true",
    )

    body_parts: list[Any] = [
        Div(
            H6(title, cls="mb-1"),
            Small(time, cls="text-muted") if time else "",
            cls="d-flex flex-wrap align-items-baseline justify-content-between gap-2",
        )
    ]
    if description:
        body_parts.append(P(description, cls="mb-1 text-muted"))
    if meta:
        body_parts.append(Div(meta, cls="mt-2"))

    return Div(marker, Div(*body_parts, cls="flex-grow-1 min-w-0"), **attrs)