Skip to main content

Introduction

Filament’s Forms package allows you to easily build dynamic, reactive forms in your Laravel applications. It’s used throughout Filament’s ecosystem - in panel resources, action modals, table filters, and more. The form builder provides a fluent API for creating fields, organizing layouts, and handling validation with both frontend and backend support. Learning how to build forms is essential to using Filament effectively. This guide will walk you through the fundamentals of the form builder.

How forms work

Forms in Filament are built using a schema-based approach. A schema is an array of components that define the structure and behavior of your form. These components include:
  • Fields - Input components for capturing data (text inputs, selects, date pickers, etc.)
  • Layout components - Components for organizing fields (sections, grids, tabs, etc.)
  • Actions - Buttons and interactive elements that can be added to forms

Creating form fields

Form field classes are found in the Filament\Forms\Components namespace. Fields are created using the static make() method, passing the field’s name:
use Filament\Forms\Components\TextInput;

TextInput::make('name')
The field name typically corresponds to a database column or model attribute. You can use dot notation to bind fields to nested array keys:
TextInput::make('settings.theme')
TextInput::make('meta.seo_title')

Building a complete form

Here’s an example of a complete form schema with multiple fields:
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Components\Section;

public function form(Schema $schema): Schema
{
    return $schema
        ->schema([
            Section::make('Post Details')
                ->schema([
                    TextInput::make('title')
                        ->required()
                        ->maxLength(255),
                    
                    Textarea::make('excerpt')
                        ->rows(3)
                        ->maxLength(500),
                    
                    Select::make('status')
                        ->options([
                            'draft' => 'Draft',
                            'published' => 'Published',
                            'archived' => 'Archived',
                        ])
                        ->required(),
                    
                    DateTimePicker::make('published_at')
                        ->label('Publish Date'),
                ])
                ->columns(2),
        ]);
}

Fluent API pattern

Filament forms use a fluent, chainable API. Each method returns the component instance, allowing you to chain multiple configuration methods:
TextInput::make('email')
    ->label('Email Address')
    ->email()
    ->required()
    ->maxLength(255)
    ->placeholder('[email protected]')
    ->helperText('We\'ll never share your email.')

Field labels

By default, field labels are automatically generated from the field name. You can customize the label using the label() method:
TextInput::make('full_name')
    ->label('Full Name')
You can also hide labels visually while keeping them accessible to screen readers:
TextInput::make('search')
    ->hiddenLabel()
    ->placeholder('Search...')

Field placeholders

Many fields support placeholders that display when the field is empty:
TextInput::make('username')
    ->placeholder('johndoe')

Select::make('country')
    ->options([
        'us' => 'United States',
        'uk' => 'United Kingdom',
        'ca' => 'Canada',
    ])
    ->placeholder('Select a country')

Default values

You can set default values for fields that are used when the form is loaded with no data:
TextInput::make('role')
    ->default('member')

Toggle::make('is_active')
    ->default(true)

DateTimePicker::make('created_at')
    ->default(now())

Disabling fields

Fields can be disabled to prevent user interaction:
TextInput::make('email')
    ->disabled()

// Conditionally disable
TextInput::make('admin_notes')
    ->disabled(fn () => ! auth()->user()->isAdmin())
Disabled fields are still included when the form is submitted. To make a field read-only and exclude it from submission, use readOnly():
TextInput::make('created_at')
    ->readOnly()

Helper text and hints

You can add helper text below a field to provide additional context:
TextInput::make('slug')
    ->helperText('This will be used in the URL for this post.')
Hints are displayed next to the label:
TextInput::make('api_token')
    ->hint('Required for API access')

Autofocus

You can autofocus a field when the form loads:
TextInput::make('name')
    ->autofocus()

Column spans

When using a grid layout, you can control how many columns a field spans:
use Filament\Schemas\Components\Grid;

Grid::make(3)
    ->schema([
        TextInput::make('first_name'), // Spans 1 column
        TextInput::make('last_name'),  // Spans 1 column
        TextInput::make('email')
            ->columnSpan(2), // Spans 2 columns
        Textarea::make('bio')
            ->columnSpan('full'), // Spans all columns
    ])

Field utility injection

Many field methods accept closures that can access various utilities through dependency injection:

Accessing other field values

Use the Get utility to access the value of other fields:
use Filament\Schemas\Components\Utilities\Get;

TextInput::make('slug')
    ->required(fn (Get $get) => filled($get('title')))

Setting other field values

Use the Set utility to modify other fields:
use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Support\Str;

TextInput::make('title')
    ->live(onBlur: true)
    ->afterStateUpdated(function (Set $set, ?string $state) {
        $set('slug', Str::slug($state));
    })

TextInput::make('slug')
    ->required()

Accessing the current component

Inject the component instance to access its methods:
use Filament\Forms\Components\TextInput;

TextInput::make('name')
    ->placeholder(fn (TextInput $component) => 
        $component->isDisabled() ? null : 'Enter your name'
    )

Accessing the Livewire component

Access the parent Livewire component:
use Livewire\Component as Livewire;

TextInput::make('team_name')
    ->default(fn (Livewire $livewire) => $livewire->currentTeam->name)

Available form fields

Filament ships with a comprehensive set of form fields:

Text Input

Basic text input field with support for various HTML input types

Select

Dropdown selection with search and multi-select support

Checkbox

Single checkbox for boolean values

Toggle

Modern toggle switch for boolean values

Radio

Radio button group for single selection

Checkbox List

Multiple checkboxes for array selection

Date & Time Pickers

Date, time, and datetime selection

File Upload

File and image upload with preview

Rich Editor

WYSIWYG editor with formatting tools

Markdown Editor

Markdown editor with preview

Repeater

Repeatable set of fields for array data

Builder

Flexible builder with multiple block types

Tags Input

Input for managing tags/keywords

Textarea

Multi-line text input

Key-Value

Key-value pair editor

Color Picker

Color selection input

Toggle Buttons

Button group for single/multiple selection

Slider

Range slider for numeric input

Code Editor

Code editor with syntax highlighting

Hidden

Hidden field for storing data

Next steps

Now that you understand the basics, explore:

Build docs developers (and LLMs) love