Skip to content

PageHeader

PageHeader renders a reusable page title, subtitle, optional eyebrow, badge, and action area.

Quick Start

from faststrap import PageHeader, Button, Badge

PageHeader(
    "Reports",
    eyebrow="Analytics",
    subtitle="Quarterly performance and exports.",
    badge=Badge("Live", variant="success"),
    actions=[
        Button("Export", variant="secondary", outline=True),
        Button("New Report", variant="primary"),
    ],
)

Parameters

Name Type Default Description
title str required Main page heading.
subtitle str | None None Muted supporting copy below the title.
eyebrow str | None None Small uppercase label above the heading.
badge Any | None None Inline badge or status element beside the title.
actions Any | list[Any] | tuple[Any, ...] | None None Right-aligned action content.
**kwargs Any {} Additional HTML/HTMX/data/ARIA attributes.

Notes

  • On small screens, the actions stack below the title.
  • On large screens, the title and actions align horizontally with justify-content-between.

API Reference

faststrap.components.layout.page_header.PageHeader(title, *, subtitle=None, eyebrow=None, badge=None, actions=None, **kwargs)

Render a page title area with optional subtitle and actions.

Source code in src/faststrap/components/layout/page_header.py
@register(category="layout")
@beta
def PageHeader(
    title: str,
    *,
    subtitle: str | None = None,
    eyebrow: str | None = None,
    badge: Any | None = None,
    actions: Any | list[Any] | tuple[Any, ...] | None = None,
    **kwargs: Any,
) -> Div:
    """Render a page title area with optional subtitle and actions."""
    user_cls = kwargs.pop("cls", "")

    title_children: list[Any] = []
    if eyebrow:
        title_children.append(Span(eyebrow, cls="text-uppercase text-muted small fw-semibold"))

    heading_children: list[Any] = [title]
    if badge is not None:
        heading_children.append(Span(badge, cls="ms-2 align-middle"))
    title_children.append(H1(*heading_children, cls="h2 mb-1"))

    if subtitle:
        title_children.append(P(subtitle, cls="text-muted mb-0"))

    children: list[Any] = [Div(*title_children)]
    if actions is not None:
        if isinstance(actions, (list, tuple)):
            action_children = list(actions)
        else:
            action_children = [actions]
        children.append(Div(*action_children, cls="d-flex flex-wrap gap-2 align-items-center"))

    attrs: dict[str, Any] = {
        "cls": merge_classes(
            "d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-3 mb-4",
            user_cls,
        )
    }
    attrs.update(convert_attrs(kwargs))
    return Div(*children, **attrs)