Files
prompts/docs/skills/nicegui-ui-customization/references/interaction-patterns.md
T
John Lancaster 3347443ca9 formatting
2026-06-19 01:29:05 -05:00

2.8 KiB

Interaction Patterns Reference

Reactive State

Use bindable dataclasses for local page state.

from dataclasses import field
from nicegui import binding, ui

@binding.bindable_dataclass
class PageState:
    selected_id: int | None = None
    items: list = field(default_factory=list)

state = PageState()
ui.label().bind_text_from(state, "selected_id")

File Upload Pattern

  • Validate extension and size before storing.
  • Delegate storage to a service method.
  • Notify success and failure explicitly.
async def handle_upload(e: ui.events.UploadEventArguments):
    try:
        if e.size > 10 * 1024 * 1024:
            raise ValueError("File too large")
        if not e.name.endswith(".pdf"):
            raise ValueError("Only PDF allowed")
        await file_service.store(e.content.read(), e.name)
        ui.notify(f"Uploaded: {e.name}", type="positive")
    except ValueError as err:
        ui.notify(str(err), type="negative")

ui.upload(on_upload=handle_upload, auto_upload=True)

Form Submission Pattern

  • Bind UI inputs to dataclass fields.
  • Perform validation in the service layer.
  • Clear form state on success.
@binding.bindable_dataclass
class FormData:
    name: str = ""
    email: str = ""

data = FormData()
ui.input("Name").bind_value(data, "name")
ui.input("Email").bind_value(data, "email")

async def on_submit():
    try:
        await user_service.create_user(name=data.name, email=data.email)
        ui.notify("User created", type="positive")
        data.name = data.email = ""
    except ValueError as err:
        ui.notify(str(err), type="negative")

ui.button("Submit").on_click(on_submit)

Real-Time Updates Decision

Use SSE for one-way status streaming. Use WebSocket for bidirectional messaging.

SSE endpoint example:

@app.get("/events/status")
async def status_stream():
    async def gen():
        while True:
            yield f"data: {await get_status()}\\n\\n"
            await asyncio.sleep(1)
    return StreamingResponse(gen(), media_type="text/event-stream")

Background Work Pattern

  • Start long jobs in FastAPI background tasks.
  • Expose status via endpoint or streaming channel.
  • Guard buttons against duplicate submissions during in-flight tasks.

Explicit Refresh Pattern

Use @ui.refreshable and call refresh intentionally instead of polling unrelated state.

@ui.refreshable
async def item_list():
    items = await service.list()
    for item in items:
        ui.label(item.name)

ui.button("Refresh").on_click(lambda: item_list.refresh())

!!! info "Primary sources" - NiceGUI action events - FastAPI server-sent events - FastAPI WebSockets