Skip to content

Basic Usage

Creating a Form Class

Create a form class that extends Form and define your fields in the fields() method. You may generate one with Artisan:

bash
php artisan make:form CreateUserForm

Or create it manually:

php
namespace App\Forms;

use InertiaUI\Forms\Fields\Submit;
use InertiaUI\Forms\Fields\TextInput;
use InertiaUI\Forms\Form;

class CreateUserForm extends Form
{
    protected ?string $actionRoute = 'users.store';

    public function fields(): array
    {
        return [
            TextInput::make('name')
                ->required()
                ->placeholder('Enter your name'),

            TextInput::make('email')
                ->email()
                ->required()
                ->placeholder('you@example.com'),

            Submit::make('Create User'),
        ];
    }
}

The $actionRoute property tells the form where to submit. It resolves to a named Laravel route. The HTTP method is automatically detected from the route definition.

Passing to Inertia

Use the static make() method to create a form instance and pass it as a prop to your page:

php
use App\Forms\CreateUserForm;

class UserController
{
    public function create()
    {
        return Inertia::render('Users/Create', [
            'form' => CreateUserForm::make(),
        ]);
    }
}

Behind the scenes, make() creates the form instance, and Inertia serializes it to JSON via the form's toArray() method. The result includes the action URL, HTTP method, field definitions, and initial data.

Rendering in Your Frontend

In your page component, import the Form component for your stack and pass the form prop:

vue
<script setup>
import { Form } from '@inertiaui/form-vue'

defineProps(['form'])
</script>

<template>
    <Form :form="form" />
</template>
tsx
import { Form } from '@inertiaui/form-react'

export default function CreateUser({ form }) {
    return <Form form={form} />
}

That's it. The component reads the field definitions and renders the appropriate input component for each field, complete with labels, help text, error messages, and styling.

Handling Submission

Submitting the form sends an Inertia request to the action URL using the configured HTTP method. On the backend, handle the request like any other Inertia form submission:

php
class UserController
{
    public function create()
    {
        return Inertia::render('Users/Create', [
            'form' => CreateUserForm::make(),
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'unique:users'],
        ]);

        User::create($validated);

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

Or use the #[Validate] attribute to let the form handle validation 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');
    }
}

See the validation docs for more on the #[Validate] attribute.

Action Routes and Methods

The simplest way to set the form action is with the $actionRoute property:

php
class CreateUserForm extends Form
{
    protected ?string $actionRoute = 'users.store';
}

The HTTP method is inferred from the route definition.

When the named route needs parameters, pass them while making the form:

php
return Inertia::render('Users/Edit', [
    'form' => EditUserForm::make()
        ->route('users.update', ['user' => $user]),
]);

For a named route, Inertia Forms always uses the HTTP method declared by that route. Calling put(), patch(), or another method helper does not override a resolved named route. Use url() when the action is a raw URL and set its method explicitly:

php
EditUserForm::make()->url('/api/users/1')->patch();

Events

The Form component accepts submission callbacks. In Vue they are emitted as events; in React they are passed as props:

vue
<template>
    <Form
        :form="form"
        @success="handleSuccess"
        @error="handleError"
        @finish="handleFinish"
    />
</template>

<script setup>
function handleSuccess() {
    // Form submitted successfully
}

function handleError(errors) {
    // Validation errors returned
}

function handleFinish() {
    // Submission finished, after either success or error
}
</script>
tsx
import { Form } from '@inertiaui/form-react'

export default function CreateUser({ form }) {
    return (
        <Form
            form={form}
            onSuccess={handleSuccess}
            onError={handleError}
            onFinish={handleFinish}
        />
    )
}

function handleSuccess() {
    // Form submitted successfully
}

function handleError(errors) {
    // Validation errors returned
}

function handleFinish() {
    // Submission finished, after either success or error
}

success / onSuccess and finish / onFinish have no payload. error / onError receives the current validation error object. finish always runs after the request completes.