Views and Events¶
The tree¶
Every piece of UI is a View. app.build() sets the root; containers hold children in controls=; views that wrap a single view take it in content=.
app.build(
nib.VStack(
controls=[
nib.Text("Hello", font=nib.Font.TITLE),
nib.HStack(
controls=[
nib.Button("OK", action=confirm),
nib.Button(content=nib.Label("Cancel", icon="xmark"), action=cancel),
],
spacing=8,
),
],
spacing=12,
padding=16,
)
)
The tree is serialised as a flat list of nodes (id, type, props, modifiers, parent and child ids) and may be at most 100 levels deep; a deeper tree raises an error naming the depth, which in practice only happens with accidental recursion.
Styling is constructor arguments¶
There is no method chaining. Every view accepts the same modifier arguments, and each one is also a reactive property:
| Group | Arguments |
|---|---|
| Layout | width, height, min_width, min_height, max_width, max_height ("infinity" fills), padding, margin, offset |
| Appearance | background (colour or view), foreground_color, fill, stroke, stroke_width (shapes), opacity, corner_radius, clip_shape, blend_mode, scale |
| Typography | font, font_weight |
| Effects | shadow_color, shadow_radius, shadow_x, shadow_y, border_color, border_width |
| Animation | animation, content_transition, transition |
| Composition | overlay, context_menu, tooltip, visible, key, ref |
| Interaction | on_drop, on_hover, on_click |
padding and margin take a number or a dict with any of top, bottom, leading, trailing, horizontal, vertical. background, overlay and context_menu may hold other views; they travel as separate nodes attached to their owner. The Modifiers reference documents each argument.
visible=False removes the view from the tree entirely; opacity=0 keeps its space.
Identity¶
Nodes are identified by their position: the root is "0", its second child "0.1", and so on. The runtime uses the id to match nodes between frames and to route events. When children are reordered or inserted, pass key="..." so a view keeps its identity (and its runtime state, such as a text field's cursor) instead of taking over the slot of a sibling. Two views in one tree must never share an id; the render fails loudly if they do.
To reach a view declared inline in app.build(...) from a handler, create a nib.Ref() before building, pass it as ref=, and read ref.current.
Events¶
Callbacks are constructor arguments. The runtime sends the node id, an event name and a typed value; the SDK calls the matching function on the event thread.
| View | Argument | Signature |
|---|---|---|
Button, MenuItem |
action |
handler() |
TextField, SecureField, TextEditor |
on_change, on_submit |
handler(text: str) |
Toggle |
on_change |
handler(is_on: bool) |
Slider |
on_change |
handler(value: float), continuously while dragging |
Picker |
on_change |
handler(value: str) |
DisclosureGroup |
on_expand |
handler(is_expanded: bool) |
NavigationStack |
on_navigate |
handler(route: str) |
Table |
on_select |
handler(selected_rows: list) |
Map |
on_region_change |
handler(latitude, longitude, zoom) |
WebView |
on_load, on_navigate, on_error |
handler(), handler(url: str), handler(message: str) |
Canvas |
on_pan_start, on_pan_update, on_pan_end, on_hover |
handler(event: PanEvent) with event.x, event.y |
| any view | on_drop |
handler(paths: list[str]) |
| any view | on_hover |
handler(is_hovering: bool) |
| any view | on_click |
handler() |
App |
on_appear, on_disappear, on_quit |
handler() |
App.on_hotkey(shortcut, handler) |
handler() |
on_appear and on_disappear fire when the popover opens and closes. on_quit fires once when the app quits and, under nib run, when the app is replaced by a reload.
A callback that raises is logged with its traceback and the app keeps running.
Related¶
- API Reference: views by category
- Modifiers Reference: all modifier arguments
- Ref:
ref=handles - Layouts: stacks, lists, grids
- Styling: colours, fonts, shapes
- Reactivity: patch model