Overview
Introduction¶
Schemas let you build user interfaces in PHP by combining components for input, display, and layout. A schema is represented by a Filament\Schemas\Schema object, and you pass its components to the components() method. Components can contain child schemas to create nested layouts.
Filament packages provide you with various components. You can find a full list in the available components section:
- Form fields accept input from the user, for example, a text input, a select, or a checkbox. They come with integrated validation.
- Infolist entries are components for rendering "description lists." Entries are key-value UI elements that can present read-only information like text, icons, and images. The data for an infolist can be sourced from anywhere but commonly comes from an individual Eloquent record.
- Layout components are used to structure the components. For example, a grid, tabs, or a multi-step form wizard.
- Prime components are simple components that are used to render basic stand-alone static content, such as text, images, and buttons (actions).
Available components¶
For building forms, Filament includes a set of fields for different data types:
- Text input
- Select
- Checkbox
- Toggle
- Checkbox list
- Radio
- Date-time picker
- File upload
- Rich editor
- Markdown editor
- Repeater
- Builder
- Tags input
- Textarea
- Key-value
- Color picker
- Toggle buttons
- Slider
- Code editor
- Hidden
- Or, build your own custom form field
For displaying data in a label-value "description list" format, Filament includes infolist entry components:
- Text entry
- Icon entry
- Image entry
- Color entry
- Code entry
- Key-value entry
- Repeatable entry
- Or, build your own custom infolist entry
To arrange components into a layout, Filament includes layout components:
- Grid
- Flex
- Fieldset
- Section
- Tabs
- Wizard
- Callout
- Empty states
- Or, build your own custom layout component
For displaying arbitrary content, Filament includes prime components:
You can also insert "action" buttons into schemas. These can run PHP functions, and even open modals. For more information, see the actions documentation.
You can learn more about building custom components to render your own Blade views in the custom components documentation.
An example schema¶
For example, you may want to build a form with a schema. The name of the schema is usually dictated by the name of the method that it is defined in (form in this example). Filament creates the Schema object and passes it to the method, which then returns the schema with the components added:
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
$schema
->components([
Grid::make(2)
->schema([
Section::make('Details')
->schema([
TextInput::make('name'),
Select::make('position')
->options([
'developer' => 'Developer',
'designer' => 'Designer',
]),
Checkbox::make('is_admin'),
]),
Section::make('Auditing')
->schema([
TextEntry::make('created_at')
->dateTime(),
TextEntry::make('updated_at')
->dateTime(),
]),
]),
])
Grid is a layout component that renders multiple components together in a responsive grid. The number of columns in the grid is specified in the make() method. The schema() method is used to nest components within the grid.
Section is another layout component that renders multiple components together in a card, with a heading at the top.
TextInput, Select, and Checkbox are form components that accept input from the user.
TextEntry is an infolist component that displays read-only information. In this example, it is used to display the created and updated timestamps of the record. The dateTime() method is used to format the timestamps as dates and times.
The schema object is the container for the components and can now be rendered. Rendering the schema will render all the components within it in the correct layout.
Component utility injection¶
The vast majority of methods used to configure entries accept functions as parameters instead of hardcoded values:
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
Grid::make()->columns(fn (): array => [
'lg' => auth()->user()->isAdmin() ? 4 : 6,
])->schema([
// ...
])
Section::make()
->heading(fn (): string => auth()->user()->isAdmin() ? 'Admin Dashboard' : 'User Dashboard')
->schema([
// ...
])
This alone unlocks many customization possibilities.
The package is also able to inject many utilities to use inside these functions, as parameters. All customization methods that accept functions as arguments can inject utilities.
These injected utilities require specific parameter names to be used. Otherwise, Filament doesn't know what to inject.
Injecting the state of another component¶
You may also retrieve the state (value) of a form field or infolist entry from within a callback, using a $get parameter:
use Filament\Schemas\Components\Utilities\Get;
function (Get $get) {
$email = $get('email'); // Store the value of the `email` entry in the `$email` variable.
//...
}
By default, Get and Set avoid resolving fresh child schemas of the component being evaluated while searching for state, but can still search its cached descendants. This prevents recursive schema evaluation. If you need to include fresh child schemas, you can call skipComponentsChildSchemasWhileSearching(false) on the utility before using it. Do not disable this protection inside a child schema callback that would resolve itself again.
Injecting the current Eloquent record¶
You may retrieve the Eloquent record for the current schema using a $record parameter:
use Illuminate\Database\Eloquent\Model;
function (?Model $record) {
// ...
}
Injecting the current operation¶
If you're writing a schema for a panel resource or relation manager, and you wish to check if a schema is create, edit or view, use the $operation parameter:
function (string $operation) {
// ...
}
Injecting the current Livewire component instance¶
If you wish to access the current Livewire component instance, define a $livewire parameter:
use Livewire\Component;
function (Component $livewire) {
// ...
}
Injecting the current component instance¶
If you wish to access the current component instance, define a $component parameter:
use Filament\Schemas\Components\Component;
function (Component $component) {
// ...
}
Injecting multiple utilities¶
The parameters are injected dynamically using reflection, so you are able to combine multiple parameters in any order:
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Livewire\Component as Livewire;
function (Livewire $livewire, Get $get, Set $set) {
// ...
}
Injecting dependencies from Laravel's container¶
You may inject anything from Laravel's container like normal, alongside utilities:
use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Http\Request;
function (Request $request, Set $set) {
// ...
}
Lazy loading a child schema¶
By default, a schema's components are rendered when the page loads. If a child schema is expensive to render, you can lazy load it when it enters the viewport using the lazyLoaded() method:
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
Section::make('Customer details')
->key('customerDetails')
->schema(
Schema::make()
->components([
TextInput::make('name'),
TextInput::make('email')
->email(),
])
->lazyLoaded(),
)
The lazy schema initially renders a loading indicator. When the loading indicator enters the viewport, only that schema is rendered in a new request. If the schema contains a validation error before it has loaded, it is loaded automatically so the validation error can be revealed.
If a lazy schema is inside a concealed component, such as a collapsed section or an inactive tab, it will not load until its parent is revealed and it enters the viewport. Once a schema has loaded, it remains loaded for the lifetime of the Livewire component.
Every lazy schema needs a unique key. In this example, the child schema inherits the customerDetails key from the section. You can instead call key() on the child schema itself. If multiple child schemas of the same component are lazy, such as a section's content and footer schemas, you must call key() on each additional schema so that they do not inherit the same key. If you lazy load the schema for a repeater item or builder block, each item schema automatically receives a unique key from its state path:
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
Repeater::make('members')
->schema(
Schema::make()
->components([
TextInput::make('name'),
TextInput::make('email')
->email(),
])
->lazyLoaded(),
)
You may also pass a boolean or function to lazyLoaded() to control it conditionally.
Setting the root heading level¶
By default, headings in a schema start at level two, since schemas are usually rendered below a page's level-one heading. If you render a schema elsewhere in the document hierarchy, you can change its root heading level using the rootHeadingLevel() method:
use Filament\Schemas\Schema;
public function productSchema(Schema $schema): Schema
{
return $schema
->rootHeadingLevel(3)
->components([
// ...
]);
}
In this example, the schema is rendered below a level-two heading, so its headings start at level three. Nested section headings automatically use the next level. Labelled repeater and builder items also advance the heading level used by components inside them.
Global settings¶
If you wish to change the default behavior of a component globally, then you can call the static configureUsing() method inside a service provider's boot() method, to which you pass a Closure to modify the component using. For example, if you wish to make all section components have 2 columns by default, you can do it like so:
use Filament\Schemas\Components\Section;
Section::configureUsing(function (Section $section): void {
$section
->columns(2);
});
Of course, you are still able to overwrite this on each component individually:
use Filament\Schemas\Components\Section;
Section::make()
->columns(1)
Restricting Livewire file uploads to schema components¶
If you build a custom Livewire component on top of InteractsWithSchemas, Livewire's file upload RPC methods accept uploads to any property path by default. See Restricting Livewire file uploads to schema components in the security documentation for the RestrictsFileUploadsToSchemaComponents trait that locks them down.