Skip to content

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

1
2
3
(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).

1
2
3
(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

1
2
3
(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.

1
2
3
4
5
(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)

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()