Field Widgets¶
Craft Easy Admin ships with 14 field widgets that render automatically based on the widget property in the schema. A central FieldRenderer component dispatches each field to the correct widget.
Widget Props¶
All widgets share a common props interface:
interface FieldWidgetProps {
name: string; // Field name
field: FieldSchema; // Full field schema definition
value: any; // Current value
onChange: (value: any) => void; // Change handler
error?: string; // Validation error message
}
Widget Catalog¶
TextInputField¶
Single-line text input for strings, emails, URLs, and passwords.
| Property | Behavior |
|---|---|
| Widget types | text, email, url, password |
| Keyboard | Adapts to widget type (email, url, default) |
| Secure entry | Enabled for password widget |
| Max length | Enforced from field.max_length |
// Rendered for: widget="text" | "email" | "url" | "password"
<TextInputField name="email" field={field} value={value} onChange={onChange} />
TextArea¶
Multi-line text input.
| Property | Behavior |
|---|---|
| Default lines | 4 |
| Scroll | Vertical scroll enabled |
| Max length | Enforced from field.max_length |
// Rendered for: widget="textarea"
<TextArea name="description" field={field} value={value} onChange={onChange} />
NumberInput¶
Numeric input with min/max clamping and step hints.
| Property | Behavior |
|---|---|
| Keyboard | Numeric |
| Parsing | Integer or float based on field.type |
| Clamping | Values clamped to field.min / field.max |
| Step | Displayed as hint from field.step |
// Rendered for: widget="number" or field.type="number"|"integer"
<NumberInput name="amount" field={field} value={value} onChange={onChange} />
Select¶
Single-value dropdown (modal-based on mobile).
| Property | Behavior |
|---|---|
| Options | From field.options |
| None option | Shown for non-required fields ("-- None --") |
| Display | Modal picker with highlighted selection |
// Rendered for: widget="select"
<Select name="status" field={field} value={value} onChange={onChange} />
MultiSelect¶
Multi-value selection with chip display.
| Property | Behavior |
|---|---|
| Value type | string[] |
| Display | Chips for selected values |
| Picker | Modal with checkboxes |
// Rendered for: widget="multiselect" | "multi_select"
<MultiSelect name="tags" field={field} value={value} onChange={onChange} />
DatePicker¶
Date-only input (YYYY-MM-DD).
| Property | Behavior |
|---|---|
| Format | ISO 8601 date (YYYY-MM-DD) |
| Keyboard | Numbers and punctuation |
| Input | Handles both Date objects and ISO strings |
// Rendered for: widget="date"
<DatePicker name="due_date" field={field} value={value} onChange={onChange} />
DateTimePicker¶
Date and time input (YYYY-MM-DD HH:mm).
| Property | Behavior |
|---|---|
| Format | YYYY-MM-DD HH:mm |
| Conversion | Normalizes space/T separators for ISO format |
| Input | Handles datetime strings and Date objects |
// Rendered for: widget="datetime"
<DateTimePicker name="starts_at" field={field} value={value} onChange={onChange} />
Toggle¶
Boolean switch component.
| Property | Behavior |
|---|---|
| Component | React Native Switch |
| Track colors | Border color (off) → primary color (on) |
| Layout | Label + help text on left, switch on right |
// Rendered for: widget="boolean" or field.type="boolean"
<Toggle name="is_active" field={field} value={value} onChange={onChange} />
FileUpload¶
File and image upload placeholder.
| Property | Behavior |
|---|---|
| Display | Dashed border dropzone |
| Accepted types | From field.accept (e.g. "image/*,.pdf") |
| Size limit | From field.max_size_mb |
| Remove | Button to clear selected file |
// Rendered for: widget="file" | "image"
<FileUpload name="document" field={field} value={value} onChange={onChange} />
RelationPicker¶
Searchable foreign-key picker with live API queries.
| Property | Behavior |
|---|---|
| Search | Queries field.relation.endpoint with search term |
| Display | Shows field.relation.label_field |
| Value | Stores field.relation.value_field |
| Filters | Applies field.relation.filters to API calls |
| Loading | Activity indicator during search |
| Clear | Button to reset selection |
// Rendered for: widget="relation" or when field.relation is defined
<RelationPicker name="tenant_id" field={field} value={value} onChange={onChange} />
TagInput¶
Chip-based tag management with add/remove.
| Property | Behavior |
|---|---|
| Value type | string[] |
| Add | Text input + "+" button, or keyboard submit |
| Remove | "x" button per chip |
| Deduplication | Duplicate tags are ignored |
// Rendered for: widget="tags" | "tag"
<TagInput name="labels" field={field} value={value} onChange={onChange} />
JsonEditor¶
JSON object editor with syntax validation.
| Property | Behavior |
|---|---|
| Lines | 6-line multi-line input |
| Font | Monospace |
| Validation | Real-time JSON parse error detection |
| Formatting | Pretty-prints on mount (JSON.stringify(value, null, 2)) |
| Placeholder | {"key": "value"} |
// Rendered for: widget="json" or field.type="json"|"dict"
<JsonEditor name="metadata" field={field} value={value} onChange={onChange} />
FieldRenderer¶
The central dispatcher that maps field.widget and field.type to the correct widget component. You typically use FieldRenderer in your views rather than individual widgets.
Mapping logic:
| Condition | Widget |
|---|---|
widget="boolean" or type="boolean" |
Toggle |
widget="textarea" |
TextArea |
widget="number" or type="number"\|"integer" |
NumberInput |
widget="select" |
Select |
widget="multiselect"\|"multi_select" |
MultiSelect |
widget="date" |
DatePicker |
widget="datetime" |
DateTimePicker |
widget="file"\|"image" |
FileUpload |
widget="relation" or field.relation defined |
RelationPicker |
widget="tags"\|"tag" |
TagInput |
widget="json" or type="json"\|"dict" |
JsonEditor |
| Everything else | TextInputField |