Skip to content

Validation

Per-Field Rules

Add validation rules to any field using the fluent API. The most common rules have dedicated methods:

php
TextInput::make('name')->required(),
TextInput::make('email')->email()->required(),
TextInput::make('age')->number()->nullable(),

Adding Custom Rules

Use rule() to add a single rule, or rules() for multiple:

php
TextInput::make('username')
    ->required()
    ->rule('alpha_dash')
    ->rule('min:3')
    ->rule('max:20'),

TextInput::make('password')
    ->password()
    ->rules(['required', 'min:8', 'confirmed']),

Rules are additive. The username field above validates with required, alpha_dash, min:3, and max:20; the later rule() calls do not replace required. The rules() method behaves the same way, and duplicate string rules are removed when the final rule list is collected.

You may pass any rule Laravel supports: strings, Rule objects, or closures:

php
use Illuminate\Validation\Rule;

TextInput::make('email')
    ->email()
    ->required()
    ->rule(Rule::unique('users', 'email')->ignore($user->id)),

Convenience Methods

These shorthand methods are available on all fields:

MethodRule Added
required()required
nullable()nullable

And on TextInput specifically:

MethodInput Type + Rule
email()email type + string, email
password()password type + string
number()number type + numeric
integer()number type + integer
url()url type + string, url
tel()tel type + string
min(5)adds min:5
max(100)adds max:100

Auto-Generated Rules

Some fields automatically add validation rules based on their configuration, so you do not have to duplicate logic.

Combobox And Radio

Providing options() automatically adds a Rule::in() constraint:

php
Combobox::make('country')
    ->options(['us' => 'United States', 'ca' => 'Canada', 'mx' => 'Mexico']),
// Auto-adds: Rule::in(['us', 'ca', 'mx'])

Multiple Combobox

Enabling multiple() adds the array rule and applies Rule::in() to each element via fieldname.*:

php
Combobox::make('languages')
    ->options(['php' => 'PHP', 'js' => 'JavaScript', 'go' => 'Go'])
    ->multiple(),
// Auto-adds: 'array' on 'languages', Rule::in(['php', 'js', 'go']) on 'languages.*'

Combobox Tokens

Calling tokens() stores an array of strings. Finite token options validate each token when custom tokens are disabled:

php
Combobox::make('topics')
    ->tokens()
    ->options(['Planning', 'Research', 'Review'])
    ->allowCustomValues(false),
// Auto-adds: 'array' on 'topics', Rule::in([...]) on 'topics.*'

Custom Values And Server-Backed Combobox

Combobox keeps finite option validation unless allowCustomValues() or searchOptionsUsing() is enabled, or the field uses remote source() options. In those cases the complete option list is not submitted with the form config, so Rule::in() is skipped:

php
Combobox::make('framework')
    ->options(['laravel' => 'Laravel', 'rails' => 'Rails'])
    ->allowCustomValues(),
// No Rule::in() added. The user may type custom values.

Slider

Calling min() and max() on a scalar slider adds min: and max: rules automatically:

php
Slider::make('rating')->min(1)->max(10),
// Auto-adds: 'min:1', 'max:10'

For range() sliders, the submitted [min, max] array is validated with array, list, and size:2. Each item gets numeric, min, and max; minStepsBetween() adds a package rule for the thumb order and minimum gap.

For generated rules that are unique to one field, see that field's documentation.

The #[Validate] Attribute

The #[Validate] attribute lets you type-hint your form in a controller method and have it validated automatically:

php
use InertiaUI\Forms\Validate;

class UserController
{
    public function store(#[Validate] CreateUserForm $form)
    {
        $validated = $form->validated();

        User::create($validated);

        return redirect()->route('users.index');
    }
}

The container creates the form, injects the current request, and calls validate() when it resolves a parameter with #[Validate]. Validation failures throw a ValidationException, and Inertia handles the redirect with errors automatically.

File upload fields may generate token or multipart file rules. The #[Validate] attribute validates those rules, but it does not hydrate temporary upload tokens into files. Read resolved SubmittedUpload objects through the helpers in File Uploads.

Accessing Validated Data

Use validated() to get only the validated data:

php
public function store(#[Validate] CreateUserForm $form)
{
    $data = $form->validated();
    // ['name' => 'Jane Example', 'email' => 'jane@example.com']
}

Manual Validation

You may validate manually without the attribute:

php
public function store(Request $request)
{
    $form = CreateUserForm::make();
    $validated = $form->validated();

    User::create($validated);
}

The form automatically receives the current request when resolved through the container. Use validate() when you only need to run validation without reading transformed values.

Precognition

Laravel Precognition gives users real-time validation feedback as they fill out the form. Precognitive fields are validated on the server when the user leaves the field (on blur).

Marking Fields

Use precognitive() on any field:

php
TextInput::make('email')
    ->email()
    ->required()
    ->precognitive(),

TextInput::make('username')
    ->required()
    ->rule(Rule::unique('users'))
    ->precognitive(),

Only fields marked as precognitive will be validated in real-time. Other fields are validated on submission as usual.

How It Works

A precognitive field blur triggers this flow:

  1. The frontend component sends a Precognition request to the form's action URL
  2. The Precognition and Precognition-Validate-Only headers tell the server which fields to validate
  3. Laravel resolves the action parameters and validates only the requested precognitive fields
  4. Validation errors are returned and displayed immediately under the field

The action route still needs Laravel's HandlePrecognitiveRequests middleware. For routes using an Inertia Forms form class, type-hint the form with #[Validate] so validation runs while Laravel resolves the action parameters. A FormRequest may also handle the request if it owns the same rules. You do not need a separate Precognition endpoint.

Custom Messages

Override the messages() method to customize error messages:

php
class CreateUserForm extends Form
{
    public function fields(): array
    {
        return [
            TextInput::make('email')->email()->required(),
            TextInput::make('name')->required()->rule('min:2'),
        ];
    }

    public function messages(): array
    {
        return [
            'email.required' => 'We need your email to create an account.',
            'email.email' => 'That doesn\'t look like a valid email address.',
            'name.min' => 'Your name must be at least :min characters.',
        ];
    }
}

Custom Attribute Names

Override the attributes() method to customize how field names appear in error messages:

php
public function attributes(): array
{
    return [
        'dob' => 'date of birth',
        'tel' => 'phone number',
    ];
}

Now instead of "The dob field is required", users see "The date of birth field is required".

Collecting Rules

The rules() method on the form collects rules from all authorized fields and returns them as a standard Laravel rules array:

php
$form = CreateUserForm::make();
$form->rules();
// [
//     'name' => ['required'],
//     'email' => ['required', 'string', 'email'],
// ]

This is the same format you'd pass to Validator::make(). The form uses this internally for validation.

KeyValue Nested Validation

The KeyValue field stores keyed mode as an associative map and single mode as a value-only list. Use valueRules() for each submitted value:

php
KeyValue::make('metadata')
    ->valueRules(['required', 'string']);

This adds:

php
[
    'metadata' => ['array'],
    'metadata.*' => ['required', 'string'],
]

In keyed mode, keyRules() validates the submitted keys at the same nested value paths:

php
KeyValue::make('metadata')
    ->keyRules(['regex:/^[a-z_]+$/'])
    ->valueRules(['required', 'string']);

Repeater Nested Validation

The Repeater field validates its nested schema fields using dot notation. Each schema field's rules are prefixed with items.*.:

php
Repeater::make('items')
    ->minItems(1)
    ->maxItems(10)
    ->schema([
        TextInput::make('name')->required(),
        TextInput::make('quantity')->number()->required()->rule('min:1'),
        TextInput::make('price')->number()->required(),
    ]),

This generates the following rules:

php
[
    'items' => ['array', 'min:1', 'max:10'],
    'items.*' => ['array'],
    'items.*.name' => ['required'],
    'items.*.quantity' => ['numeric', 'required', 'min:1'],
    'items.*.price' => ['numeric', 'required'],
]

Blocks Nested Validation

The Blocks field validates its structural shape first, then validates nested schema fields for the submitted block type at each request index. Submitted values use type and data keys:

php
Blocks::make('content')
    ->maxItems(10)
    ->sets([
        BlockSet::make('hero')
            ->maxItems(1)
            ->schema([
                TextInput::make('headline')->required(),
            ]),

        BlockSet::make('quote')->schema([
            Textarea::make('quote')->required(),
        ]),
    ]);

A request with a hero at index 0 and a quote at index 1 generates request-indexed nested rules such as:

php
[
    'content' => ['array', 'max:10', /* per-set max validation */],
    'content.*' => ['array'],
    'content.*.type' => ['required', 'string', Rule::in(['hero', 'quote'])],
    'content.*.data' => ['required', 'array'],
    'content.0.data.headline' => ['required'],
    'content.1.data.quote' => ['required'],
]

The top-level content value is always validated as an array. Blocks::maxItems() adds the normal Laravel max: rule to that array, while each BlockSet::maxItems() adds custom per-type validation that counts submitted items by type and fails when one set appears too many times. Nested schema rules are generated only for the block type submitted at each request index. See Blocks nested validation for the field-level explanation.