Skip to content

Toast

Toasts are lightweight, non-blocking notifications. They are designed to mimic the push notifications popularized by mobile and desktop operating systems.

Bootstrap Reference

Bootstrap 5 Toasts


Quick Start

In FastStrap, we use SimpleToast for the most common case: a simple text message with a variant color.

Live Preview
SimpleToast("Success! Item added to cart.", variant="success")

Visual Examples & Use Cases

1. SimpleToast Variants

Standard colors to communicate status.

Code & Output

SimpleToast("File uploaded.", variant="info")
SimpleToast("Connection lost.", variant="danger")

2. Full Control (Standard Toast)

For rich content, headers, and custom timing, use the base Toast component.

Code & Output

Live Preview (Rich Toast)
Toast(
    "Your message has been sent.",
    title="Messenger",
    cls="shadow-sm",
    delay=5000
)

3. Toast Container

Toasts are often grouped. FastStrap handles the ToastContainer logic to ensure they stack correctly in the corner of the screen.

from faststrap import ToastContainer, add_bootstrap

# 1. Add container to your main layout
app_layout = [
    MainView(),
    ToastContainer(position="bottom-end") # Global container
]

Practical Functionality

1. Triggering Toasts via HTMX

The most common implementation is to return a Toast as part of an HTMX response (using hx-swap="beforeend" targetting the Toast Container).

@app.route("/add_item")
def add_item():
    # ... logic ...
    return SimpleToast("Item Added", variant="success") # Appends to existing list

Parameter Reference

FastStrap Param Type Bootstrap Attribute Description
title Any .toast-header Optional header element/text.
autohide bool data-bs-autohide If True, closes automatically.
delay int data-bs-delay Duration in milliseconds before closing.
duration (SimpleToast) int CSS animation delay Duration in milliseconds before fade out.
position str - Location: top-end, bottom-start, etc.

faststrap.components.feedback.toast.SimpleToast(*children, title=None, variant=None, duration=None, position=None, **kwargs)

Simple Toast component that works without JavaScript.

Source code in src/faststrap/components/feedback/toast.py
@register(category="feedback")
def SimpleToast(
    *children: Any,
    title: str | None = None,
    variant: VariantType | None = None,
    duration: int | None = None,
    position: ToastPositionType | None = None,
    **kwargs: Any,
) -> Div:
    """Simple Toast component that works without JavaScript."""
    # Resolve API defaults
    cfg = resolve_defaults("SimpleToast", variant=variant, duration=duration, position=position)

    c_variant = cfg.get("variant", "info")
    c_duration = cfg.get("duration", 5000)
    c_position = cfg.get("position", "top-right")

    # Build base classes
    classes = ["alert", f"alert-{c_variant}", "alert-dismissible", "fade", "show"]

    # Position classes for fixed overlay
    position_classes = {
        "top-right": "position-fixed top-0 end-0 m-3",
        "top-left": "position-fixed top-0 start-0 m-3",
        "bottom-right": "position-fixed bottom-0 end-0 m-3",
        "bottom-left": "position-fixed bottom-0 start-0 m-3",
        "top-center": "position-fixed top-0 start-50 translate-middle-x m-3",
        "bottom-center": "position-fixed bottom-0 start-50 translate-middle-x m-3",
        "top-start": "position-fixed top-0 start-0 m-3",
        "top-end": "position-fixed top-0 end-0 m-3",
        "bottom-start": "position-fixed bottom-0 start-0 m-3",
        "bottom-end": "position-fixed bottom-0 end-0 m-3",
    }

    classes.append(position_classes.get(c_position, position_classes["top-right"]))

    # Merge with user classes
    user_cls = kwargs.pop("cls", "")
    all_classes = merge_classes(" ".join(classes), user_cls)

    # Build attributes
    attrs: dict[str, Any] = {
        "cls": all_classes,
        "role": "alert",
        "style": "z-index: 9999; max-width: 400px;",
    }

    # Add CSS for auto-hide
    if c_duration > 0:
        duration_ms = int(c_duration)
        # Backward compatibility: historical API used seconds.
        if duration_ms <= 50:
            warnings.warn(
                "SimpleToast(duration=...) now expects milliseconds; "
                "values <= 50 are treated as seconds for compatibility.",
                DeprecationWarning,
                stacklevel=2,
            )
            duration_ms *= 1000
        duration_seconds = duration_ms / 1000
        style = (
            f"animation: toastFadeOut {duration_seconds}s ease-in-out "
            f"{duration_seconds}s forwards;"
        )
        existing_style = attrs.get("style", "")
        if existing_style:
            attrs["style"] = f"{existing_style}; {style}"
        else:
            attrs["style"] = style

    # Convert remaining kwargs
    attrs.update(convert_attrs(kwargs))

    # Build toast structure
    parts = []

    if title:
        header = Div(
            Strong(title, cls="me-auto"),
            Button(
                type="button",
                cls="btn-close",
                aria_label="Close",
            ),
            cls="alert-heading",
        )
        parts.append(header)

    body = Div(*children, cls="mb-0")
    parts.append(body)

    return Div(*parts, **attrs)