Form Widgets
A Widget is the input that a generated form renders for one field. This page shows each widget as FormModel renders it. A widget can carry chrome that its primitive lacks: a picker trigger, a remove control, a preview, or a notice in place of an input. The Inputs and Date + Time pages show the primitives that the widgets use. Components describes the skin rules that every component page shares.
Every demo runs against one seeded model with one field per widget. The caption under each demo names the field's typeSerializer and typeModel pair, which selects the widget through the type mapping tables. Field and Widget Resolution describes the lookup.
Date and time
Four widgets cover date and time fields. The date widgets show editable segments and a trigger that opens a calendar. The time widgets show editable segments only. Each range widget shows both bounds on one row.
A time range with an error marks both bounds invalid.
Read-only dates
A read view, a computed field, or a read-only model config renders a field without its input. Date, time, and datetime fields then render with WidgetDateTimeReadOnly, which formats the value. Its display options come from the mapping entry's readOnlyWidgetProps. They match the columnProps of the list column for the same type, so a field reads the same in a list and on a read view. An empty date renders the same dash in both.
Duration
WidgetDuration enters a duration through one spinner per time unit. Only showMinutes defaults to true; showDays, showHours, and showSeconds add the other units. Each spinner has a visible unit label, and clicking the label focuses its input. The WidgetDuration.unitLabel slot styles the labels.
The value is the duration string that a DurationField sends and reads, such as 1 02:30:00. With seconds, the value is a number of seconds, as a DurationSecondsField sends and reads it. The shown units split the value between them, so two days read as 48 hours when days are hidden. Clearing a unit while the rest of the value is zero sets the value to null. Entering 0 keeps a zero duration.
A negative value, such as -1 23:00:00 (Django's form for minus one hour), shows a "Negative" segment with a minus sign before the spinners. The spinners show the size of the duration, and editing them keeps the value negative. The WidgetDuration.sign and WidgetDuration.signSymbol slots style that segment.
Read-only durations
Read-only duration fields render with WidgetDurationReadOnly, which names the units that the value holds. A DurationField sends 2 08:00:00, and the read row shows "2 days, 8 hours". A DurationSecondsField sends a number of seconds, which the same widget reads. Units that hold zero are left out, and a duration of zero names its smallest unit ("0 seconds"). An empty value renders the same dash as an empty date. A list cell uses ColumnDuration, which wraps the same display, so a field reads the same in both places.
Choice
A single choice renders WidgetSelectDropdown. The demo below shows the other two choice widgets: a many-valued choice, and a boolean with labels for its two states.
WidgetSelectDropdown treats empty-string, null, and undefined choices as no selection and leaves them out of the menu. Without a placeholder, it uses the first empty choice's label as the placeholder. The values false and 0 stay in the menu as ordinary choices. The menu has no empty item, so a user cannot clear a selection from it.
Lists of values
WidgetTagsInput enters a list of values as removable tags. Its value is an array of strings. The widget adds an entry on Enter, on a comma, on paste, and when the input loses focus. It trims each entry first, so 2 next to an existing 2 is a duplicate, and the widget does not add it. With numeric, the widget adds only decimal numbers, such as 12, -2.5, or 1e3.
The widget keeps a refused entry, such as 1..2, in the input and marks it invalid until the user edits it. A DecimalInField filter, such as a list of IDs, renders this widget.
Structured data
WidgetJson edits a JSON field as text and submits the parsed value.
Read-only JSON
Read-only JSON fields render with WidgetJsonReadOnly, which prints the payload over several lines, indented by indent spaces per level (2 by default). A list cell uses ColumnJson, which prints the same value compact and truncates it past maxLength characters (200 by default). Both render a null value as the same dash as an empty date. An empty object or array is a recorded value, so it reads as {} or [].
Files and images
Each widget shows an upload control while the field is empty. Once the field has a file, WidgetFile shows it as a download link with remove and download controls, and WidgetImage shows a preview with a remove control.
In a read view, both field types render with WidgetFileReadOnly, which shows the file as a link labelled with the file name, or a dash when the field is empty.
Unmapped widget
IP address fields map to WidgetUnmapped by default. It renders an alert that names the field in place of an input, so the field stays visible on the form. The alert sits in the field's content column and must not look like a control. Map a Field Type to a Widget describes how to give the type a widget, and the error that a field with no mapping renders.