Toasts are lightweight, non-blocking notifications. They are designed to mimic the push notifications popularized by mobile and desktop operating systems.
For rich content, headers, and custom timing, use the base Toast component.
Code & Output
Live Preview (Rich Toast)
Messenger
Just now
Your message has been sent.
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.
fromfaststrapimportToastContainer,add_bootstrap# 1. Add container to your main layoutapp_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")defadd_item():# ... logic ...returnSimpleToast("Item Added",variant="success")# Appends to existing list
@register(category="feedback",requires_js=True)defToast(*children:Any,title:str|None=None,variant:VariantType|None=UNSET,autohide:bool|None=UNSET,delay:int|None=UNSET,animation:bool|None=UNSET,**kwargs:Any,)->Div:"""Bootstrap Toast component for temporary notifications."""# Resolve API defaultscfg=resolve_defaults("Toast",variant=variant,autohide=autohide,delay=delay,animation=animation)c_variant=cfg.get("variant")c_autohide=cfg.get("autohide",True)c_delay=cfg.get("delay",5000)c_animation=cfg.get("animation",True)# Build base classesclasses=["toast"]ifc_variant:classes.append(f"text-bg-{c_variant}")# Merge with user classesuser_cls=kwargs.pop("cls","")all_classes=merge_classes(" ".join(classes),user_cls)# Build attributesattrs:dict[str,Any]={"cls":all_classes,"role":"alert","aria-live":"assertive","aria-atomic":"true",}# Bootstrap toast data attributesifc_autohide:attrs["data-bs-autohide"]="true"attrs["data-bs-delay"]=str(c_delay)else:attrs["data-bs-autohide"]="false"ifc_animation:attrs["data-bs-animation"]="true"# Convert remaining kwargsattrs.update(convert_attrs(kwargs))# Build toast structureparts=[]iftitle:header=Div(Strong(title,cls="me-auto"),Button(type="button",cls="btn-close",data_bs_dismiss="toast",aria_label="Close",),cls="toast-header",)parts.append(header)body=Div(*children,cls="toast-body")parts.append(body)returnDiv(*parts,**attrs)
@register(category="feedback")defToastContainer(*toasts:Any,position:ToastPositionType|None=UNSET,container_id:str="toast-container",**kwargs:Any,)->Div:"""Container for positioning toasts on the page."""# Resolve API defaultscfg=resolve_defaults("ToastContainer",position=position)c_position=cfg.get("position","top-end")# Build position classesclasses=["toast-container","position-fixed","p-3"]position_map={"top-start":"top-0 start-0","top-center":"top-0 start-50 translate-middle-x","top-end":"top-0 end-0","middle-start":"top-50 start-0 translate-middle-y","middle-center":"top-50 start-50 translate-middle","middle-end":"top-50 end-0 translate-middle-y","bottom-start":"bottom-0 start-0","bottom-center":"bottom-0 start-50 translate-middle-x","bottom-end":"bottom-0 end-0",}classes.append(position_map.get(c_position,position_map["top-end"]))# Merge with user classesuser_cls=kwargs.pop("cls","")all_classes=merge_classes(" ".join(classes),user_cls)# Build attributesexplicit_id=kwargs.pop("id",None)ifexplicit_idisnotNoneandexplicit_id!=container_id:raiseValueError("ToastContainer received both container_id and id with different values; ""use container_id only.")attrs:dict[str,Any]={"cls":all_classes,"id":container_id}attrs.update(convert_attrs(kwargs))returnDiv(*toasts,**attrs)