3.2 KiB
Binding Dataclasses Deep Dive
Use this reference to model NiceGUI state with bindable dataclasses and avoid common propagation and performance pitfalls.
Primary Sources
- NiceGUI binding docs: binding properties
- Python dataclass docs: dataclasses module
- Data class design rationale: PEP 557
Bindable Dataclass Behavior
@binding.bindable_dataclass extends standard dataclasses by turning fields into bindable properties, allowing UI bindings to propagate when a field is assigned.
from nicegui import binding, ui
@binding.bindable_dataclass
class Profile:
name: str = "Ada"
age: int = 37
profile = Profile()
ui.input("Name").bind_value(profile, "name")
ui.number("Age", min=0).bind_value(profile, "age")
ui.label().bind_text_from(profile, "name", backward=lambda name: f"User: {name}")
Propagation And Performance
NiceGUI distinguishes between two link types:
- Bindable properties propagate efficiently when values are assigned.
- Active links are checked in a refresh loop.
Prefer bindable dataclasses for frequently updated form state. Keep binding transforms pure and inexpensive. If an application has many active links, tune binding_refresh_interval in ui.run(...) only after measuring the impact.
Dataclass Modeling Rules
- Use
field(default_factory=...)for mutable defaults. - Avoid
frozen=Truefor models edited by UI controls. - Use
slots=Trueonly after confirming compatibility with inheritance and extension needs. - Keep UI-editable fields explicit and typed.
from dataclasses import field
from nicegui import binding
@binding.bindable_dataclass
class Filters:
query: str = ""
tags: list[str] = field(default_factory=list)
Nested Structures
NiceGUI supports tuple paths for nested data structures.
from nicegui import ui
data = {"user": {"name": "Ada"}}
ui.input("Name").bind_value(data, ("user", "name"))
ui.label().bind_text_from(data, ("user", "name"))
Keep nested dataclass updates explicit and predictable at the field level.
Strictness And Refactor Safety
- Object attributes are checked by default.
- Dictionary keys are not checked by default.
- Use
strict=Truewhen missing dictionary keys should produce warnings.
from nicegui import app, ui
ui.input().bind_value(app.storage.user, "display_name", strict=True)
Common Pitfalls
- In-place mutation may not produce immediate UI synchronization. Assign the updated value back to the bound field.
- Heavy binding transforms can degrade refresh performance. Move expensive work to event handlers or services.
- State shared across unrelated pages or users can leak data. Scope models to the appropriate page, client, or user context.
Version Checks
bindable_dataclasswas added in NiceGUI 2.11.0.- Depth-first binding propagation was documented in NiceGUI 2.16.0.
- Binding
strictbehavior was documented in NiceGUI 3.0.0. - Tuple paths for nested properties were documented in NiceGUI 3.10.0.
Verify these behaviors against the NiceGUI version pinned by the target project.