Field Types
The form widget renders one field for each definition in its YAML, and the field's type picks how it renders. This page covers the built-in types and the options each one takes, followed by the properties every field shares. Form widgets, such as the color picker, have pages of their own, and Building a Form Page shows how to put a form on a page and save it.
Each definition is keyed by the field name, which is the model attribute the field reads and saves. Where the fields sit, in tabs or side by side, is covered in Layout.
Text
text is the default type, so a field with no type renders a single line input. placeholder shows while the field is empty. The input is limited to 255 characters unless attributes sets its own maxlength.
fields:
code:
label: Code
placeholder: auroraDeskLamp
comment: No type is given, so this is a text field.
headline:
label: Headline
type: text
placeholder: Write a headline
comment: The placeholder shows while the field is empty.Email
email renders an email input, which brings up the email keyboard on phones and lets the browser check the format. The browser check is a convenience, so validate the value on the model as well, here with the email rule (see Validation).
fields:
email:
label: Email
type: email
placeholder: name@example.com
comment: The browser checks the format, and the model's email rule checks it again on save.Number
number passes min, max and step to the input. With no step, any decimal is accepted and the spinner is hidden. The value is saved as a number, and an empty field saves as null, so a nullable column is cleared rather than set to zero.
fields:
price:
label: Price
type: number
span: left
min: 0
step: 0.01
placeholder: '0.00'
comment: From zero, in steps of one cent.
quantity:
label: Quantity
type: number
span: right
min: 0
max: 999
step: 1
comment: Whole numbers from 0 to 999.Password
password always renders empty, so a stored password is never sent back to the browser. When the form saves through the FormModelSaver trait (see Building a Form Page), a field name that starts with an underscore is set on the model but removed before the record is written. This example uses one, so its value is never stored.
fields:
_password:
label: Password
type: password
placeholder: Type anything
comment: Never saved, because the name starts with an underscore.Textarea
textarea renders a multi-line input. In preview mode it shows the text with its line breaks.
fields:
description:
label: Description
type: textarea
placeholder: Describe the sampleTextarea sizes
size sets the height of a textarea: tiny, small, large (the default), huge or giant. The same sizes apply to the editor widgets, such as the code editor.
fields:
excerpt:
label: Excerpt
type: textarea
size: tiny
span: left
comment: size tiny
summary:
label: Summary
type: textarea
size: small
span: right
comment: size small
body:
label: Body
type: textarea
size: huge
comment: size huge
notes:
label: Notes
type: textarea
size: giant
comment: size giantDropdown
dropdown renders a searchable select from its options, keyed by the value that is saved. emptyOption adds a first option with an empty value, so picking it clears the field. placeholder prompts while the field is empty and adds a clear button in place of an empty option. showSearch: false removes the search box, which suits a short list.
fields:
priority:
label: Priority
type: dropdown
span: left
emptyOption: Not set
options:
low: Low
normal: Normal
high: High
comment: Not set can be picked again to clear the value.
delivery:
label: Delivery
type: dropdown
span: right
placeholder: Choose a method
showSearch: false
options:
pickup: Pick up in store
courier: Courier
post: Post
comment: The placeholder shows while it is empty, and the search box is off.A read-only dropdown, or one in preview mode, shows the label of its value as text instead of a select.
Options from the model
With no options, the field calls get{Field}Options on the model, where {Field} is the field name in studly case, so the country field calls getCountryOptions. optionsMethod names any other model method, or a static method written as Class::method. An option with optgroup: true and children becomes an option group, as getCategoryOptions returns here. Radio lists, checkbox lists and balloon selectors take their options the same ways; Option lists has the full order and the arguments each method receives.
fields:
country:
label: Country
type: dropdown
span: left
comment: No options are given, so they come from the model's getCountryOptions method.
category:
label: Category
type: dropdown
span: right
emptyOption: Pick a category
optionsMethod: getCategoryOptions
comment: From the method named by optionsMethod, which returns option groups.
currency:
label: Currency
type: dropdown
span: left
optionsMethod: App\Models\Sample::listCurrencies
comment: From a static method, named as Class::method./**
* getCountryOptions returns the countries that start the dependent dropdown chain.
*
* @return array<string, string>
*/
public function getCountryOptions(): array
{
return [
'au' => 'Australia',
'nz' => 'New Zealand',
'us' => 'United States',
];
}/**
* getCategoryOptions returns the category choices grouped under option group headings.
*
* @return array<string, array{optgroup: bool, children: array<string, string>}>
*/
public function getCategoryOptions(): array
{
return [
'Furniture' => [
'optgroup' => true,
'children' => [
'chairs' => 'Chairs',
'desks' => 'Desks',
'shelving' => 'Shelving',
],
],
'Lighting' => [
'optgroup' => true,
'children' => [
'ceiling' => 'Ceiling Lights',
'lamps' => 'Lamps',
],
],
];
}/**
* listCurrencies returns the currency choices, as a static options method named by optionsMethod.
*
* @return array<string, string>
*/
public static function listCurrencies(self $sample, FormField $field): array
{
return [
'aud' => 'Australian Dollar',
'nzd' => 'New Zealand Dollar',
'usd' => 'US Dollar',
];
}Option presets
optionsPreset fills the options from a built-in list: icons@phosphor and icons@bootstrap list every Phosphor and Bootstrap icon with its preview, locales lists language codes with their native names, flags and flags@short list the same codes with a flag, and timezones lists every timezone with its UTC offset. icons lists the classes of the oc-icon-* icon font. You can register lists of your own, see Presets.
fields:
icon:
label: Icon
type: dropdown
emptyOption: No icon
optionsPreset: icons@phosphor
comment: The icons@phosphor preset lists every Phosphor icon, each with its preview.Option colors and icons
An option written as [label, value] shows a status dot when the second value is a hex color, an image when it is a path (any value with a dot in it), and an icon otherwise. An option can also be detailed, an array with label and any of icon, color, image, comment, disabled and children, written in the YAML or returned by a model method. Children are indented below their parent. A disabled option cannot be picked, unless it is the saved value, which stays selectable so that saving the form keeps it.
fields:
stock_status:
label: Stock Status
type: dropdown
span: left
options:
in_stock: [In stock, '#27ae60']
low: [Low stock, '#f39c12']
out: [Out of stock, '#e74c3c']
comment: A second value that is a hex color shows a status dot.
transport:
label: Transport
type: dropdown
span: right
options:
road: [Road, ph ph-truck]
air: [Air, ph ph-airplane-tilt]
sea: [Sea, ph ph-boat]
comment: Any other second value is an icon.
level:
label: Level
type: dropdown
emptyOption: Pick a level
comment: Detailed options from getLevelOptions, with icons, a color, a disabled entry and indented children.The level field has no options in the YAML, so they come from getLevelOptions:
/**
* getLevelOptions returns options with icons, colors, comments, a disabled entry and child options.
*
* @return array<string, array<string, mixed>>
*/
public function getLevelOptions(): array
{
return [
'basic' => [
'label' => 'Basic',
'comment' => 'Included with every plan',
'icon' => 'ph ph-cube',
],
'pro' => [
'label' => 'Professional',
'comment' => 'Adds priority support',
'color' => '#3498db',
'children' => [
'pro-monthly' => 'Professional, billed monthly',
'pro-yearly' => 'Professional, billed yearly',
],
],
'legacy' => [
'label' => 'Legacy',
'comment' => 'No longer offered',
'icon' => 'ph ph-archive',
'disabled' => true,
],
];
}Radio list
radio picks one option from a list. inlineOptions puts the options side by side. An option written as [label, description] shows the description under its label, and a detailed option can be disabled. A radio list with no options shows its placeholder instead.
fields:
size:
label: Size
type: radio
span: left
inlineOptions: true
options:
s: Small
m: Medium
l: Large
comment: inlineOptions puts the options side by side.
plan:
label: Plan
type: radio
span: right
options:
starter: [Starter, For a single person]
team: [Team, For up to ten people]
business: [Business, For any number of people]
enterprise:
label: Enterprise
comment: Talk to our sales team
disabled: trueCheckbox
checkbox saves 1 when ticked. A hidden input posts 0 when it is not, so unticking the box is saved too. The label and comment sit beside the box rather than above it. Cast the attribute to boolean on the model to read it as true or false.
fields:
has_discount:
label: Offer a discount
type: checkbox
comment: The label and comment sit beside the box.Switch
switch saves like a checkbox, drawn as a switch.
fields:
is_featured:
label: Featured
type: switch
comment: Saved as a boolean, cast on the model.Checkbox list
checkboxlist ticks any number of options and saves the ticked keys as an array, so the attribute needs a JSON column with an array cast, or a place in $jsonable. An empty value is posted when nothing is ticked, so clearing the list is saved too. quickselect adds Select All and Select None buttons, and a click with Shift held sets every box between it and the previous click to the same state. inlineOptions puts the options on one line.
fields:
features:
label: Features
type: checkboxlist
inlineOptions: true
quickselect: true
options:
wifi: Wi-Fi
parking: Parking
pool: Pool
gym: Gym
comment: Saved as a JSON array of the ticked keys.Nested options
Options with children nest below their parent, and each option can carry a comment. With cumulative, ticking a parent ticks all of its children too. Unticking the parent leaves them as they are. Every option, parent or child, saves its own key.
fields:
permissions:
label: Permissions
type: checkboxlist
cumulative: true
options:
content:
label: Manage content
comment: Ticks every content permission below it
children:
content_create: Create entries
content_publish: Publish entries
users:
label: Manage users
children:
users_invite: Invite users
users_remove: Remove usersLong lists
A list of more than ten options scrolls inside a box, shows the Select All and Select None buttons unless quickselect: false turns them off, and stacks its options even with inlineOptions.
fields:
interests:
label: Interests
type: checkboxlist
options:
astronomy: Astronomy
baking: Baking
calligraphy: Calligraphy
climbing: Climbing
cycling: Cycling
gardening: Gardening
hiking: Hiking
knitting: Knitting
painting: Painting
photography: Photography
pottery: Pottery
sailing: Sailing
surfing: Surfing
woodworking: WoodworkingBalloon selector
balloon-selector picks one option from a row of pills and stores it in a hidden input, which suits a short list of states. Each option is focusable, and Enter or Space picks the focused one.
fields:
status:
label: Status
type: balloon-selector
options:
draft: Draft
active: Active
archived: Archived
comment: Click an option, or tab to one and press Enter or Space.Clearing a balloon selector
By default a balloon selector always holds one of its options once one is picked. allowEmpty lets the active option be clicked again to clear the value.
fields:
visibility:
label: Visibility
type: balloon-selector
allowEmpty: true
options:
public: Public
members: Members
private: Private
comment: Clicking the active option clears the value.Read-only balloon selector
With readOnly, the options leave the tab order and ignore clicks and keys, while the hidden input still posts the value, so saving the form keeps it. A disabled balloon selector looks the same but its value is left out of the saved data.
fields:
audience:
label: Audience
type: balloon-selector
readOnly: true
options:
retail: Retail
trade: Trade
wholesale: Wholesale
comment: Ignores clicks and keys, while its value still saves.Section
section renders a heading from label and a line of text from comment, to open a group of fields. displayMode: simple shows the label as plain text instead of a heading. Sections, hints and rulers post nothing, so their names only need to be unique; starting them with an underscore keeps them clear of your attribute names. A section can also collapse the fields below it, see Collapsible sections.
fields:
_shipping_section:
label: Shipping details
type: section
comment: Where and how the sample is sent.
_cost_section:
label: The fields below work out the delivery cost.
type: section
displayMode: simpleHint
hint renders a callout from label and comment. mode sets its style: info (the default), tip, which looks like info, success, warning or danger. The comment is read as Markdown, or as HTML with commentHtml.
fields:
_info_hint:
label: Info
type: hint
mode: info
comment: The default mode, which tip also uses.
_success_hint:
label: Success
type: hint
mode: success
comment: With commentHtml, the comment can hold <strong>HTML markup</strong>.
commentHtml: true
_warning_hint:
label: Warning
type: hint
mode: warning
comment: Without commentHtml, the comment is read as **Markdown**.
_danger_hint:
label: Danger
type: hint
mode: dangerHint from a partial
With path, the hint renders a partial inside the callout, so it can show values from the record. The partial has $formModel, $field and $value in scope. The label and mode still apply, and a comment renders above the partial. path takes a PHP partial, where ~ is the application root, or a namespaced view such as shop::hints.stock.
fields:
_record_hint:
label: Before you publish
type: hint
mode: warning
path: ~/resources/views/reference/forms/_hint_record_checklist.php<ul class="mb-0">
<li>
<?= e($formModel->name ?: 'This record') ?> needs a price before it can go on sale.
</li>
<li>
The slug <code><?= e($formModel->slug ?: 'not set') ?></code> becomes part of its address.
</li>
</ul>Ruler
ruler draws a horizontal line between fields, with an optional label above it and a comment below.
fields:
_ruler:
type: ruler
_packaging_ruler:
label: Packaging
type: ruler
comment: A ruler can carry a label and a comment.Partial
partial renders a partial from path, with $formModel, $field and $value in scope, for anything the built-in types do not cover. The label and comment still render around it. This one reads the form model to show which record the form edits.
fields:
_record_card:
label: Record
type: partial
path: ~/resources/views/reference/forms/_field_record_card.php
comment: The partial reads the form model, so it shows the saved record.<?php /* A partial field that reads the form model, showing which record the form edits and when it was last saved */ ?>
<div class="reference-forms-inline">
<strong>
<?= e($formModel->name) ?>
</strong>
<span class="badge theme-secondary">
<?= $formModel->exists ? 'Record '.e($formModel->getKey()) : 'New record' ?>
</span>
<span class="fg-3">
<?= $formModel->updated_at ? 'Saved '.e($formModel->updated_at->diffForHumans()) : 'Not saved yet' ?>
</span>
</div>A partial with its own input
A partial can render its own input, named with $field->getName() and given $field->getId(), and the form then saves it like any other field. This one renders a custom select with data-handler, so the dropdown loads its options from a handler on the controller as you type. The handler receives the typed text as term and returns a list of id and text pairs under results.
fields:
timezone:
label: Timezone
type: partial
path: ~/resources/views/reference/forms/_field_timezone.php
comment: After two letters, the dropdown searches the controller's onSearchTimezones handler.<?php /* A partial field rendering a dropdown that loads its options from the controller's onSearchTimezones handler */ ?>
<select
id="<?= $field->getId() ?>"
name="<?= $field->getName() ?>"
class="form-control custom-select"
data-handler="onSearchTimezones"
data-minimum-input-length="2"
data-ajax--delay="300"
data-placeholder="Type two letters to search">
<option value=""></option>
<?php if ($formModel->timezone): ?>
<option value="<?= e($formModel->timezone) ?>" selected>
<?= e(str_replace('_', ' ', $formModel->timezone)) ?>
</option>
<?php endif ?>
</select><?php
namespace App\Controllers\Reference\FormsController;
/**
* FieldsHandlers holds the AJAX handlers of the Field Types page.
*/
trait FieldsHandlers
{
/**
* onSearchTimezones returns the timezones matching the typed term, in the format the AJAX dropdown of the timezone partial field expects.
*
* @return array{results: array<int, array{id: string, text: string}>}
*/
public function onSearchTimezones(): array
{
$term = strtolower(trim((string) input('term')));
$results = collect(timezone_identifiers_list())
->filter(fn (string $zone) => $term === '' || str_contains(strtolower($zone), $term))
->take(20)
->map(fn (string $zone) => ['id' => $zone, 'text' => str_replace('_', ' ', $zone)])
->values()
->all();
return ['results' => $results];
}
}Field properties
Every field takes these properties, where they apply to its type.
| Property | Description |
|---|---|
| label | the text shown above the field, or beside a checkbox or switch. |
| type | the field type: one of the types on this page, or a form widget such as colorpicker. Default: text. |
| span | where the field sits: left, right, full, auto, row or adaptive. See Spans. Default: full. |
| spanClass | the grid column classes of a row field, such as md:col-6. See Rows. |
| size | the height of a field that has one, such as a textarea: tiny, small, large, huge or giant. Default: large. |
| placeholder | text shown while the field is empty. |
| comment | text below the field. See Comments. |
| commentAbove | text between the label and the field. |
| commentHtml | renders the comments as HTML instead of escaping them. Default: false. |
| tooltip | an icon beside the label that shows a hint, as text or as an array of title, icon, placement and isHtml. See Tooltips. |
| default | the value of the field on a new record. For option fields, the key of the option to select. See Default values. |
| defaultFrom | another attribute of the record to take the default value from. |
| valueFrom | another attribute to read the value from, while the field still posts under its own name. |
| tab | the tab the field belongs to, for fields under tabs or secondaryTabs. See Tabs. |
| order | a number that sets the position of the field. Default: 100, 200 and so on, in the order the fields are defined. |
| cssClass | a class on the element that wraps the field. See Container class and attributes. |
| attributes | HTML attributes for the input itself. See Input attributes. |
| containerAttributes | HTML attributes for the element that wraps the field. |
| stretch | makes the field fill the height of its container, for a large editor. Default: false. |
| autoFocus | puts the cursor in the field when the page loads. Default: false. |
| readOnly | stops the field from being changed while still posting its value. See Read-only fields. Default: false. |
| disabled | locks the field and leaves it out of the saved data. See Disabled fields. Default: false. |
| hidden | does not render the field, and leaves it out of the saved data. Default: false. |
| required | shows the required marker beside the label, without checking anything. The model's validation rules set it for you. See Validation. |
| context | the form contexts the field appears in, such as create or update. A name such as reference@create does the same. See Contexts. |
| dependsOn | the fields that redraw this field when they change. See Dependent fields. |
| changeHandler | an AJAX handler called when the field changes. See Change handler. |
| trigger | a condition on another field that shows, hides, enables, disables, empties or fills this one in the browser. See Triggers. |
| preset | fills the field from another one as you type. See Input presets. |
| permissions | the gate abilities the user needs for the field to appear. With a list, any one of them is enough. When the user has none of them, the field is removed from the form. |
| options | the choices of an option field. See Option lists. |
| path | the partial of a partial or hint field. |
Type options
The options each type takes besides the common properties. text, email, password, checkbox, switch and ruler take only the common properties.
Number
| Option | Description |
|---|---|
| min | the lowest value the input accepts. |
| max | the highest value the input accepts. |
| step | the interval between values, and shows the spinner. Default: any decimal, with no spinner. |
Textarea
| Option | Description |
|---|---|
| size | the height: tiny, small, large, huge or giant. Default: large. |
Dropdown
| Option | Description |
|---|---|
| options | the options, as a list or the name of a model method. See Option lists. |
| optionsMethod | a model method, or a static Class::method, that returns the options. |
| optionsPreset | a built-in list of options, such as timezones. See Presets. |
| emptyOption | the label of a first option with an empty value, which clears the field. |
| placeholder | text shown while the field is empty, with a clear button. It also adds an empty option when there is no emptyOption. |
| showSearch | shows a search box above the options. Default: true. |
Radio list
| Option | Description |
|---|---|
| options, optionsMethod, optionsPreset | the options, as for a dropdown. |
| inlineOptions | puts the options side by side. Default: false. |
| placeholder | text shown when there are no options. |
Checkbox list
| Option | Description |
|---|---|
| options, optionsMethod, optionsPreset | the options, as for a dropdown. |
| inlineOptions | puts the options side by side, for lists of up to ten. Default: false. |
| quickselect | adds Select All and Select None buttons. Default: false, or true with more than ten options. |
| cumulative | ticking a parent option ticks its children. Default: false. |
| emptyOption | text shown when there are no options. |
| placeholder | text shown in preview mode when nothing is ticked. |
Balloon selector
| Option | Description |
|---|---|
| options, optionsMethod, optionsPreset | the options, as for a dropdown. |
| allowEmpty | clicking the active option again clears the value. Default: false. |
Section
| Option | Description |
|---|---|
| displayMode | simple shows the label as plain text instead of a heading. |
Hint
| Option | Description |
|---|---|
| mode | the style of the callout: info, tip, success, warning or danger. Default: info. |
| path | a partial to render inside the callout. |
Partial
| Option | Description |
|---|---|
| path | the partial to render, a PHP file under ~/ (the application root) or a namespaced view such as shop::fields.card. |
Option lists
The dropdown, radio, checkboxlist and balloon-selector types need a list of options, each keyed by the value that is saved. The field takes the first of these that it finds:
optionsas a list in the YAML.optionsPreset, a preset name.optionsMethod, the name of a model method, or a static method written asClass::method.optionsas a string, read likeoptionsMethod.options: preset:timezonesreads a preset.- Otherwise,
get{Field}Optionson the model, and failing thatgetDropdownOptions.
The methods receive these arguments, and all of them return the options as an array:
| Method | Arguments |
|---|---|
a model method named by optionsMethod or options | ($value, $fieldName, $data) |
a static Class::method | ($model, $field), the model and the FormField |
get{Field}Options | ($value, $data) |
getDropdownOptions | ($attribute, $value, $data), where $attribute is the field name |
While a form refreshes, such as for a dependent field, the model holds the posted values, so a method can read the other fields from $this.
Option formats
Each option can be written in any of these ways:
| Format | Result |
|---|---|
key: Label | a plain option. |
key: [Label, Second] | in a dropdown, a status dot when Second is a hex color, an image when it is a path, and an icon class otherwise. Radio and checkbox lists show it as a description under the label. |
key: { label: ..., ... } | a detailed option, taking label, comment, icon, color, image, disabled and children. |
key: { optgroup: true, children: ... } | an option group in a dropdown, with the key as its heading. |
Presets
optionsPreset takes one of the built-in lists: icons, icons@phosphor, icons@bootstrap, locales, flags, flags@short or timezones. To add your own list, register it in a service provider's boot method with PresetManager::instance()->registerPreset('priorities', fn () => [...]), using Larajax\Ui\Classes\PresetManager. extendPreset takes a callback that receives a list's items and returns them changed, and replacePreset swaps a list for another.