Common Property Options
Every property type supports these shared options. Chain them fluently on any property.
Validation
| (new StringProperty('name'))->required() // field must have a value
(new StringProperty('name'))->notNull() // alias for required()
|
Labels & Hints
| (new StringProperty('ref'))->label('Reference Number') // custom label
(new StringProperty('ref'))->placeholder('e.g. REF-001') // placeholder hint
(new StringProperty('ref'))->autofocus() // focus on page load
|
Info
Labels are auto-generated from the property name: 'first_name' becomes 'First Name'. Use ->label() only when the auto-generated label isn't right.
Visibility & Read-Only
Control whether a field appears in the form and whether it can be edited.
| // Static
(new StringProperty('internal_note'))->hidden()
(new StringProperty('status'))->readonly()
// Dynamic — receives the current record
(new StringProperty('approval_note'))
->visible(fn($record) => $record->status === 'review')
(new StringProperty('reference'))
->readonly(fn($record) => !$record->isNew())
|
Visibility Shortcuts in beforeRender()
For more complex logic, use beforeRender() in your model:
| protected function beforeRender(): void
{
// Show field only for superadmins
$this->getProperty('admin_notes')?->setVisible(Auth::isSuperAdmin());
// Make field readonly after first save
$this->readonlyAfterInsert('reference');
// Hide parent reference after first save (it can't change)
$this->hiddenAfterInsert('contract_id');
// Show field only after first save
$this->visibleAfterInsert('feedback');
}
|
Array Mode
Store multiple values per field (e.g. multiple emails, tags, file attachments).
| (new EmailProperty('watchers'))->asArray() // unlimited
(new PdfProperty('documents'))->asArray(0, 3) // 0 to 3 items
(new StringProperty('tags'))->asArray()->min(1) // at least 1
|
Array values are stored in a system table (e.g. sys_email, sys_string) and rendered as tag pills or a list.
Array Display Modes
| (new StringProperty('skills'))->asArray()->arrayDisplay('pills') // default: tag pills
(new StringProperty('steps'))->asArray()->arrayDisplay('list') // vertical list
(new StringProperty('items'))->asArray()->arrayDisplay('tiles') // card tiles
|
Calculated Fields
Make any property computed from other field values. The field becomes read-only and updates live via AJAX as the user edits the form.
| (new DateRangeProperty('period'))
->setReadonly(true)
->setFunction(function ($record) {
return [$record->start_date, $record->end_date ?: date('Y-m-d')];
})
|
Warning
The closure receives the model instance. Use $record->field_name to access values. The computed result is persisted to the database.
Table View
Control which fields appear as columns in the multi-record table view.
| (new StringProperty('name'))->inTable() // show in table view
(new TextProperty('notes'))->inTable(false) // hide from table view (default)
|
Search
Control whether a field is included in full-text search.
| (new StringProperty('name'))->searchable() // included in search (default for text fields)
(new StringProperty('internal_id'))->searchable(false) // exclude from search
|
Calendar
Exclude date fields from calendar views.
| (new DateProperty('internal_deadline'))->calendarDisable() // not shown on calendar
|
Transient Fields
A transient field has no database column. It is rendered in the form but must be populated via hooks.
| (new StringProperty('confirmation_code'))->transient()
|