Skip to content

Switcher

@experimental

Responsive adaptive panel layout. Displays side-by-side on desktop and switches to stacked single-column on mobile. Ideal for summary cards, settings pages, and split-content layouts.


Quick Start

from faststrap.components.layout import Switcher
from faststrap import Card

Switcher(
    Card("Chart goes here", header="Revenue"),
    Card("Stats go here", header="Summary"),
    breakpoint="md",
    gap=3,
)

Features

  • Automatic side-by-side to stacked transition at a configurable breakpoint
  • Equal or custom column ratio via CSS Grid
  • Configurable gap between panels
  • Works with any FastHTML/Faststrap content
  • Pure CSS — no JavaScript required

Parameters

Parameter Type Default Description
*children Any required Two or more panel contents
breakpoint "sm" \| "md" \| "lg" \| "xl" \| "xxl" "md" Breakpoint to switch from column to row
ratio str \| None None CSS grid-template-columns (e.g. "1fr 2fr")
gap int \| str 3 Bootstrap gap utility value or custom CSS gap string
min_item_width str \| None None Minimum width before items wrap when using ratio
**kwargs Any Extra wrapper attributes

Usage Examples

Basic Side-by-Side

from faststrap import Card, Switcher

Switcher(
    Card("Left panel"),
    Card("Right panel"),
    breakpoint="md",
    gap=4,
)

Custom Column Ratio

Switcher(
    Card("Sidebar", header="Navigation"),
    Card("Main content", header="Dashboard"),
    ratio="1fr 3fr",
    breakpoint="lg",
)

Minimum Item Width

Switcher(
    Card("A"),
    Card("B"),
    Card("C"),
    ratio="repeat(auto-fit, minmax(250px, 1fr))",
    min_item_width="250px",
)

Notes

  • Pure CSS layout using Bootstrap flex utilities or CSS Grid.
  • Different from SplitPane — Switcher is not resizable and is designed for content that should reflow, not be split.
  • Marked @experimental.

API Reference

faststrap.components.layout.switcher.Switcher(*children, breakpoint='md', ratio=None, gap=3, min_item_width=None, **kwargs)

Responsive layout that switches from row to column at a breakpoint.

Pure CSS — no JavaScript required.

Parameters:

Name Type Description Default
*children Any

Panel contents to render side-by-side on desktop.

()
breakpoint str

Bootstrap breakpoint to switch from row to column. One of "sm", "md", "lg", "xl", "xxl".

'md'
ratio str | None

Optional CSS grid-template-columns value, e.g. "1fr 2fr". When omitted, Bootstrap flex utilities are used.

None
gap int | str

Bootstrap gap utility value or custom CSS gap string.

3
min_item_width str | None

Optional minimum width before items wrap when using ratio.

None
**kwargs Any

Additional HTML attributes for the wrapper.

{}

Returns:

Type Description
Div

FastHTML Div element with responsive grid/flex layout.

Source code in src/faststrap/components/layout/switcher.py
@register(category="layout")
@experimental
def Switcher(
    *children: Any,
    breakpoint: str = "md",
    ratio: str | None = None,
    gap: int | str = 3,
    min_item_width: str | None = None,
    **kwargs: Any,
) -> Div:
    """Responsive layout that switches from row to column at a breakpoint.

    Pure CSS — no JavaScript required.

    Args:
        *children: Panel contents to render side-by-side on desktop.
        breakpoint: Bootstrap breakpoint to switch from row to column.
            One of ``"sm"``, ``"md"``, ``"lg"``, ``"xl"``, ``"xxl"``.
        ratio: Optional CSS ``grid-template-columns`` value, e.g.
            ``"1fr 2fr"``. When omitted, Bootstrap flex utilities are used.
        gap: Bootstrap gap utility value or custom CSS gap string.
        min_item_width: Optional minimum width before items wrap when
            using ``ratio``.
        **kwargs: Additional HTML attributes for the wrapper.

    Returns:
        FastHTML ``Div`` element with responsive grid/flex layout.
    """
    user_cls = kwargs.pop("cls", "")

    classes = ["faststrap-switcher"]
    style_parts: list[str] = []

    if ratio:
        classes.append("faststrap-switcher-grid")
        style_parts.append(f"grid-template-columns: {ratio}")
        if min_item_width:
            style_parts.append(f"grid-auto-columns: {min_item_width}")
    else:
        bp = _BREAKPOINT_MAP.get(breakpoint, "md")
        classes.append("d-flex")
        classes.append("flex-column")
        classes.append(f"flex-{bp}-row")

    gap_cls = f"gap-{gap}" if isinstance(gap, int) else gap
    classes.append(gap_cls)

    attrs: dict[str, Any] = {
        "cls": merge_classes(" ".join(classes), user_cls),
    }
    if style_parts:
        attrs["style"] = "; ".join(style_parts)
    attrs.update(convert_attrs(kwargs))
    return Div(*children, **attrs)