Skip to content

Fields

Fields are the building blocks of a form. Lattice ships Text input, Textarea, Select, Choice, Checkbox, Toggle, Date input, Time input, Date time input, Number input, Password input, Hidden input, File upload, Rich editor, Repeater, and Builder — and you can add your own. Each field type has its own page for the options unique to it; this page covers the options every field shares.

The submit button is not a field: the form renders it for you from ->submitLabel(). See Overview for how to customize or replace it.

For validation and conditional behavior — which also apply to every field — see Validation and Conditional fields.

The options below extend the base Field class, so they work the same on every field. The examples use TextInput, but the methods are identical everywhere.

make() takes the field name and an optional label. Pass the label as the second argument, or set it later with ->label(). Omit it and the field renders without a visible label.

TextInput::make('name', 'Team name');
TextInput::make('name')->label('Team name');

->value() seeds the field with a starting value. On a form bound to a record, the record’s value wins; otherwise this default is used.

TextInput::make('name', 'Team name')
->value('Acme Inc')

->helperText() adds a line of descriptive text beneath the field; ->hint() is an alias that reads more naturally for short tips. It renders muted, below the input and above any validation message.

TextInput::make('slug', 'Slug')
->helperText('Used in the public URL for your team.')

->labelAction() renders a component at the end of the field’s label row — typically a link, such as a “Forgot password?” link beside a password field:

use Lattice\Ui\Components\Link;
PasswordInput::make('password', 'Password')
->labelAction(Link::make('Forgot password?')->href(route('password.request')));

Any component works in the slot, so a badge or a button carrying an action fits the same way. Fields without a label row — HiddenInput, Checkbox, and fields rendered inside a repeater’s table layout — drop the label action.

->required() marks the field as required, adding the indicator and a required validation rule.

TextInput::make('name', 'Team name')
->required()

->disabled() renders the field non-interactive. A disabled field is not submitted with the form.

TextInput::make('name', 'Team name')
->value('Acme Inc')
->disabled()

->readOnly() shows the value but prevents editing. Like a disabled field, a read-only field’s typed value is not trusted on submit — Lattice drops user input for locked fields and only submits a server-set ->value() (as in the example below).

TextInput::make('slug', 'Slug')
->value('acme-inc')
->readOnly()

->hidden() drops the field from the rendered form entirely — it is absent from the payload and its validation is skipped, exactly like every other Lattice component’s shared render gate. ->visible() is the inverse and reads more naturally when toggling on a condition. Both accept a boolean or a closure resolved once per request with Lattice’s closure evaluation utilities.

TextInput::make('internal_note', 'Internal note')->hidden();
TextInput::make('internal_note', 'Internal note')->visible($user->isAdmin());
TextInput::make('internal_note', 'Internal note')->visible(fn ($user) => $user?->isAdmin() ?? false);

This is a one-time server decision, not a reactive one — for a field that should show or hide as the user fills in the rest of the form, use ->visibleWhen() instead.

When the reason is permission rather than state, reach for ->can() instead of a ->visible() closure. It takes the same abilities as a definition’s can attribute argument, and ->visible() cannot widen it:

TextInput::make('salary', 'Salary')->can('payroll.view');

See Authorization for how can behaves across pages, definitions, and components.

To show or hide a field based on another field’s value, see Conditional fields.