nicegui consolidation

This commit is contained in:
John Lancaster
2026-07-29 23:37:48 -05:00
parent bc0d6ede49
commit 8f26051a52
9 changed files with 242 additions and 435 deletions
@@ -1,119 +1,100 @@
# Binding Dataclasses Deep Dive
This reference explains how to model state with NiceGUI bindable dataclasses and how to avoid common update and performance pitfalls.
Use this reference to model NiceGUI state with bindable dataclasses and avoid common propagation and performance pitfalls.
## Primary Sources
- NiceGUI binding docs: [Binding properties](https://www.nicegui.io/documentation/section_binding_properties)
- NiceGUI binding docs: [binding properties](https://www.nicegui.io/documentation/section_binding_properties)
- Python dataclass docs: [dataclasses module](https://docs.python.org/3/library/dataclasses.html)
- Data class design rationale: [PEP 557](https://peps.python.org/pep-0557/)
## What bindable_dataclass changes
## Bindable Dataclass Behavior
`@binding.bindable_dataclass` extends standard dataclasses by turning fields into bindable properties so UI bindings can propagate immediately when a field is assigned.
Baseline pattern:
`@binding.bindable_dataclass` extends standard dataclasses by turning fields into bindable properties, allowing UI bindings to propagate when a field is assigned.
```python
from nicegui import binding, ui
@binding.bindable_dataclass
class Profile:
name: str = 'Ada'
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 n: f'User: {n}')
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 model and performance
## Propagation And Performance
NiceGUI distinguishes between two link types:
- Bindable properties: efficient, event-like propagation on assignment.
- Active links: polled in a refresh loop (default every 0.1s).
- Bindable properties propagate efficiently when values are assigned.
- Active links are checked in a refresh loop.
Practical implications:
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.
- Prefer bindable dataclasses for frequently updated form state.
- Keep transform functions pure and side-effect free.
- If many active links exist, tune `binding_refresh_interval` in `ui.run(...)` carefully.
## Dataclass modeling rules that matter for binding
## Dataclass Modeling Rules
- Use `field(default_factory=...)` for mutable defaults.
- Avoid `frozen=True` for models that should be edited from UI controls.
- Use `slots=True` only when you have confirmed compatibility with your inheritance and extension needs.
- Avoid `frozen=True` for models edited by UI controls.
- Use `slots=True` only after confirming compatibility with inheritance and extension needs.
- Keep UI-editable fields explicit and typed.
Example with safe mutable defaults:
```python
from dataclasses import field
from nicegui import binding
@binding.bindable_dataclass
class Filters:
query: str = ''
query: str = ""
tags: list[str] = field(default_factory=list)
```
## Nested structures and binding paths
## Nested Structures
NiceGUI supports nested key paths via tuples for nested data (for example dictionaries and nested structures).
NiceGUI supports tuple paths for nested data structures.
```python
from nicegui import ui
data = {'user': {'name': 'Ada'}}
data = {"user": {"name": "Ada"}}
ui.input('Name').bind_value(data, ('user', 'name'))
ui.label().bind_text_from(data, ('user', 'name'))
ui.input("Name").bind_value(data, ("user", "name"))
ui.label().bind_text_from(data, ("user", "name"))
```
When using nested dataclasses, keep updates explicit and predictable at the field level.
Keep nested dataclass updates explicit and predictable at the field level.
## Strictness and refactor safety
Binding can warn when attributes do not exist.
## Strictness And Refactor Safety
- Object attributes are checked by default.
- Dictionary keys are not checked by default.
- Use `strict=True` when you want missing-key warnings for dict-backed state.
- Use `strict=True` when missing dictionary keys should produce warnings.
```python
from nicegui import app, ui
ui.input().bind_value(app.storage.user, 'display_name', strict=True)
ui.input().bind_value(app.storage.user, "display_name", strict=True)
```
## Common pitfalls and safer alternatives
## Common Pitfalls
- Pitfall: mutating nested mutable values in place and expecting immediate UI sync.
- Safer alternative: assign back to the bound field after updates so change propagation is explicit.
- 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.
- Pitfall: heavy transform functions in bindings.
- Safer alternative: keep transformations cheap and deterministic; move heavy work to event handlers.
## Version Checks
- Pitfall: one model shared across unrelated pages or users.
- Safer alternative: scope model instances to page/client/user context as needed.
- `bindable_dataclass` was added in NiceGUI 2.11.0.
- Depth-first binding propagation was documented in NiceGUI 2.16.0.
- Binding `strict` behavior was documented in NiceGUI 3.0.0.
- Tuple paths for nested properties were documented in NiceGUI 3.10.0.
## Version notes to remember
- `bindable_dataclass` added in NiceGUI 2.11.0.
- Binding `strict` behavior documented as added in NiceGUI 3.0.0.
- Tuple paths for nested properties documented as added in NiceGUI 3.10.0.
- Depth-first binding propagation update documented in NiceGUI 2.16.0.
Verify behavior against the NiceGUI version pinned in your project before relying on version-specific semantics.
## Quick checklist
- Choose bindable dataclasses for interactive form-like state.
- Use `default_factory` for mutable fields.
- Keep transform functions pure.
- Use strict mode intentionally.
- Re-check version notes before migration work.
Verify these behaviors against the NiceGUI version pinned by the target project.