Flash Messages
Flash messages provide temporary feedback to users — save confirmations, validation errors, status updates. They live on the socket and are automatically available in your templates.
Setting Flash Messages
Call put_flash on the socket with a string key and any value:
async def handle_event(self, event, payload, socket): if event == "save": await save_record(payload) socket.put_flash("info", "Record saved.")The key is a convention you choose. Most apps use info and error, but you can use whatever makes sense:
socket.put_flash("info", "Settings updated.")socket.put_flash("error", "Could not connect to server.")socket.put_flash("warning", "Your session expires in 5 minutes.")Values can be anything — strings, dicts, dataclasses. The framework stores them; your template decides how to render them.
socket.put_flash("error", { "title": "Validation failed", "fields": ["email", "name"]})Each key holds one value. Setting the same key again replaces the previous message:
socket.put_flash("info", "First")socket.put_flash("info", "Second") # "First" is goneRendering Flash Messages
Flash is automatically available in every template as flash:
{% if flash.info %}<div class="flash-info" id="flash-info"> {{ flash.info }}</div>{% endif %}
{% if flash.error %}<div class="flash-error" id="flash-error"> {{ flash.error }}</div>{% endif %}Dismissing Flash Messages
Users expect to dismiss notifications. The built-in lv:clear-flash event handles this — just use phx-click with phx-value-key:
<div class="flash-info" phx-click="lv:clear-flash" phx-value-key="info"> {{ flash.info }}</div>That’s it. The click sends lv:clear-flash to the server with {"key": "info"}, the framework clears it, and the next render removes the element.
To clear all flash messages at once from the server side, omit the key:
socket.clear_flash() # clear everythingsocket.clear_flash("info") # clear just one keyAdding a client-side transition
If you want an instant hide before the server round-trip, chain a JS command:
<div class="flash-info" id="flash-info" phx-click='{{ js.push("lv:clear-flash", {"key": "info"}) | js.hide("#flash-info") }}'> {{ flash.info }}</div>This hides the element immediately on the client and clears the flash on the server. In practice the websocket round-trip is fast enough that the simple phx-value-key approach works well.
Complete Example
A form with success and error feedback using t-string templates:
from dataclasses import dataclassfrom string.templatelib import Template
from pyview import LiveView, LiveViewSocketfrom pyview.events import AutoEventDispatch, eventfrom pyview.meta import PyViewMetafrom pyview.template.template_view import TemplateViewfrom typing import Optional
@dataclassclass Context: name: str = ""
class SettingsLiveView(AutoEventDispatch, TemplateView, LiveView[Context]): async def mount(self, socket: LiveViewSocket[Context], _session): socket.context = Context()
@event async def save(self, name: Optional[str], socket: LiveViewSocket[Context]): if not name: socket.put_flash("error", "Name cannot be blank.") return
socket.context.name = name socket.clear_flash() socket.put_flash("info", f"Saved — welcome, {name}!")
def template(self, assigns: Context, meta: PyViewMeta) -> Template: name = assigns.name
banners = [ t'<p class="{key}" phx-click="lv:clear-flash" phx-value-key="{key}">{msg}</p>' for key, msg in meta.flash.items() ]
return t""" {banners}
<form phx-submit="save"> <input type="text" name="name" value="{name}" /> <button type="submit">Save</button> </form> """