Runtime objects¶
These objects are created automatically during form instantiation and rendering. You interact with them at render time (configuring how a field is displayed) and at validation time (reading values and errors).
BoundField¶
BoundField
¶
Runtime adapter for one field within one form instance.
Created by Field.bind() during BaseForm.__init__. Not a Textual
widget — it is a plain Python object that owns a :class:FieldController
and knows how to produce either a raw inner widget (__call__) or a
fully-composed FieldWidget (simple_layout).
_label_style and _help_style are resolved once at bind time
(field-explicit > form default) and are immutable thereafter. Any
per-render overrides are computed inline by simple_layout /
__call__ and passed directly to the widget — they are never stored
here.
__call__
¶
Return the raw inner widget (Input / Checkbox / Select / TextArea).
The returned widget has ._field_controller stamped on it so that
a :class:~textual_wtf.ControllerAwareLayout ancestor can route
Textual widget events back to the controller.
Call this when you want full layout freedom — place the widget inside
any Textual container you like. Use simple_layout() when you
want the bundled label + input + help + error chrome.
simple_layout
¶
simple_layout(
*,
label_style=None,
help_style=None,
disabled=None,
required=None,
renderer=None,
**widget_kwargs,
)
Return a :class:~textual_wtf.FieldWidget (label + input + help + error).
Render options are resolved fresh on each call:
call-site kwarg > bind-time default (form cascade > field explicit).
Nothing is stored on this BoundField; all resolved values are
passed directly into the FieldWidget.
Pass renderer=callable to override the entire inner layout; the
callable receives this BoundField and must return a
ComposeResult.
FieldController¶
FieldController
¶
Holds the runtime value, error state, and validation logic for one field.
A plain Python class — no Textual inheritance. Created by
BoundField.__init__; referenced by the BoundField and (when mounted)
by a FieldWidget.
Listeners¶
_value_listeners
Called when value is set externally (programmatic assignment,
set_data, etc.). Signature: (new_value: Any) -> None.
Not fired during widget-event handling to avoid circular updates.
_error_listeners
Called whenever the error state changes.
Signature: (has_error: bool, error_messages: list[str]) -> None.
Fired by _set_errors, _clear_errors, and add_error.
add_value_listener
¶
Register a callback invoked on external value changes.
remove_value_listener
¶
Deregister a previously registered value-change callback.
add_error_listener
¶
Register a callback invoked on any error-state change.
remove_error_listener
¶
Deregister a previously registered error-state callback.
handle_widget_input
¶
Process a value change originating from the inner widget.
Updates _value, runs event validators, and notifies error listeners.
Does not fire value listeners (to avoid syncing the value back into
the widget that just provided it). Returns whether the field is
currently valid for this event.
FieldWidget¶
FieldWidget
¶
Bases: Container
Textual Container that renders a BoundField as label + input + help + error.
Returned by BoundField.simple_layout(). Connects to the field's
:class:~textual_wtf.FieldController via listeners so that:
- Widget events (typing, blur, …) are forwarded to the controller.
- Programmatic changes (
bf.value = x, form-leveladd_error) are reflected in the UI automatically.
Pass a renderer callable to BoundField.simple_layout(renderer=…)
to override the entire compose subtree. The callable receives the
BoundField and must return a ComposeResult.
watch__external_value
¶
Sync a programmatic value change into the inner widget.
FieldErrors¶
FieldErrors
¶
Bases: Label
A label that subscribes to a :class:~textual_wtf.FieldController and
displays its current error messages, hiding itself when the field is valid.
Use this alongside a raw bf() widget when building custom layouts that
don't use :meth:~textual_wtf.BoundField.simple_layout::
yield Label(bf.field.label)
yield bf()
yield FieldErrors(bf.controller)
The widget registers itself with the controller on mount and automatically updates whenever the error state changes. It deregisters itself on unmount, so its lifetime is independent of the controller's.
FieldWidget uses FieldErrors internally for its own error display,
so both code paths share the same mechanism.