filament/schemas
Schema building tools for Filament: define, transform, and validate structured data for resources and forms with a simple, composable API. Lightweight package aimed at consistent schema definitions and reuse across your Filament app.
import Aside from "@components/Aside.astro" import UtilityInjection from "@components/UtilityInjection.astro"
You may use a "view" component to insert a Blade view into a schema arbitrarily:
use Filament\Schemas\Components\View;
View::make('filament.schemas.components.chart')
This assumes that you have a resources/views/filament/schemas/components/chart.blade.php file.
You may pass data to this view through the viewData() method:
use Filament\Schemas\Components\View;
View::make('filament.schemas.components.chart')
->viewData(['data' => $data])
You may pass an array of child schema components to the schema() method of the component:
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\View;
View::make('filament.schemas.components.chart')
->schema([
TextInput::make('subtotal'),
TextInput::make('total'),
])
Inside the Blade view, you may render the component's schema() using the $getChildSchema() function:
<div>
{{ $getChildSchema() }}
</div>
Inside the Blade view, you may access the state of another component in the schema using the $get() function:
<div>
{{ $get('email') }}
</div>
Inside the Blade view, you may access the current Eloquent record using the $record variable:
<div>
{{ $record->name }}
</div>
Inside the Blade view, you may access the current operation, usually create, edit or view, using the $operation variable:
<p>
[@if](https://github.com/if) ($operation === 'create')
This is a new post.
[@else](https://github.com/else)
This is an existing post.
[@endif](https://github.com/endif)
</p>
Inside the Blade view, you may access the current Livewire component instance using $this:
[@php](https://github.com/php)
use Filament\Resources\Users\RelationManagers\PostsRelationManager;
[@endphp](https://github.com/endphp)
<p>
[@if](https://github.com/if) ($this instanceof PostsRelationManager)
You are editing posts the of a user.
[@endif](https://github.com/endif)
</p>
Inside the Blade view, you may access the current component instance using $schemaComponent. You can call public methods on this object to access other information that may not be available in variables:
<p>
[@if](https://github.com/if) ($schemaComponent->getState())
This is a new post.
[@endif](https://github.com/endif)
</p>
You may insert a Livewire component directly into a schema:
use App\Livewire\Chart;
use Filament\Schemas\Components\Livewire;
Livewire::make(Chart::class)
If you are rendering multiple of the same Livewire component, please make sure to pass a unique key() to each:
use App\Livewire\Chart;
use Filament\Schemas\Components\Livewire;
Livewire::make(Chart::class)
->key('chart-first')
Livewire::make(Chart::class)
->key('chart-second')
Livewire::make(Chart::class)
->key('chart-third')
You can pass an array of parameters to a Livewire component:
use App\Livewire\Chart;
use Filament\Schemas\Components\Livewire;
Livewire::make(Chart::class, ['bar' => 'baz'])
<UtilityInjection set="schemaComponents" version="5.x">As well as allowing a static value, the make() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
Now, those parameters will be passed to the Livewire component's mount() method:
class Chart extends Component
{
public function mount(string $bar): void
{
// ...
}
}
Alternatively, they will be available as public properties on the Livewire component:
class Chart extends Component
{
public string $bar;
}
You can access the current record in the Livewire component using the $record parameter in the mount() method, or the $record property:
use Illuminate\Database\Eloquent\Model;
class Chart extends Component
{
public function mount(?Model $record = null): void
{
// ...
}
// or
public ?Model $record = null;
}
Please be aware that when the record has not yet been created, it will be null. If you'd like to hide the Livewire component when the record is null, you can use the hidden() method:
use Filament\Schemas\Components\Livewire;
use Illuminate\Database\Eloquent\Model;
Livewire::make(Chart::class)
->hidden(fn (?Model $record): bool => $record === null)
You may allow the component to lazily load using the lazy() method:
use Filament\Schemas\Components\Livewire;
use App\Livewire\Chart;
Livewire::make(Chart::class)
->lazy()
You may create your own custom component classes and views, which you can reuse across your project, and even release as a plugin to the community.
To create a custom component class and view, you may use the following command:
php artisan make:filament-schema-component Chart
This will create the following component class:
use Filament\Schemas\Components\Component;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
public static function make(): static
{
return app(static::class);
}
}
It will also create a view file at resources/views/filament/schemas/components/chart.blade.php.
You may use the same utilities as you would when inserting a Blade view into a schema to render the component's child schema, access another component's live state, access the current Eloquent record, access the current operation, access the current Livewire component instance, and access the current component instance.
You may add a public method to the custom component class that accepts a configuration value, stores it in a protected property, and returns it again from another public method:
use Filament\Schemas\Components\Component;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
protected ?string $heading = null;
public static function make(): static
{
return app(static::class);
}
public function heading(?string $heading): static
{
$this->heading = $heading;
return $this;
}
public function getHeading(): ?string
{
return $this->heading;
}
}
Now, in the Blade view for the custom component, you may access the heading using the $getHeading() function:
<div>
{{ $getHeading() }}
</div>
Any public method that you define on the custom component class can be accessed in the Blade view as a variable function in this way.
To pass the configuration value to the custom component class, you may use the public method:
use App\Filament\Schemas\Components\Chart;
Chart::make()
->heading('Sales')
Utility injection is a powerful feature of Filament that allows users to configure a component using functions that can access various utilities. You can allow utility injection by ensuring that the parameter type and property type of the configuration allows the user to pass a Closure. In the getter method, you should pass the configuration value to the $this->evaluate() method, which will inject utilities into the user's function if they pass one, or return the value if it is static:
use Closure;
use Filament\Schemas\Components\Component;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
protected string | Closure | null $heading = null;
public static function make(): static
{
return app(static::class);
}
public function heading(string | Closure | null $heading): static
{
$this->heading = $heading;
return $this;
}
public function getHeading(): ?string
{
return $this->evaluate($this->heading);
}
}
Now, you can pass a static value or a function to the heading() method, and inject any utility as a parameter:
use App\Filament\Schemas\Components\Chart;
Chart::make()
->heading(fn (Product $record): string => "{$record->name} Sales")
You may accept a configuration value in the make() constructor method of the custom component and pass it to the corresponding setter method:
use Closure;
use Filament\Schemas\Components\Component;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
protected string | Closure | null $heading = null;
public function __construct(string | Closure | null $heading = null)
{
$this->heading($heading)
}
public static function make(string | Closure | null $heading = null): static
{
return app(static::class, ['heading' => $heading]);
}
public function heading(string | Closure | null $heading): static
{
$this->heading = $heading;
return $this;
}
public function getHeading(): ?string
{
return $this->evaluate($this->heading);
}
}
Sometimes you need to call a method on the component class from JavaScript in the Blade view. For example, you might want to fetch data asynchronously or perform some server-side computation. Filament provides a way to expose methods on your component class to JavaScript using the #[ExposedLivewireMethod] attribute.
To expose a method to JavaScript, add the #[ExposedLivewireMethod] attribute to a public method on your custom component class:
use Filament\Schemas\Components\Component;
use Filament\Support\Components\Attributes\ExposedLivewireMethod;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
public static function make(): static
{
return app(static::class);
}
#[ExposedLivewireMethod]
public function getChartData(): array
{
// Fetch and process chart data...
return $chartData;
}
}
In your Blade view, you may call the exposed method using $wire.callSchemaComponentMethod(). The first argument is the component's key (available via $getKey()), and the second argument is the method name. You may pass arguments as a third argument:
[@php](https://github.com/php)
$key = $getKey();
[@endphp](https://github.com/endphp)
<div
x-data="{
data: null,
async loadData() {
this.data = await $wire.callSchemaComponentMethod(
[@js](https://github.com/js)($key),
'getChartData',
)
},
}"
x-init="loadData"
>
<template x-if="data">
{{-- Render the chart using the data --}}
</template>
</div>
You may pass arguments to the method by providing an object as the third argument:
[@php](https://github.com/php)
$key = $getKey();
[@endphp](https://github.com/endphp)
<div
x-data="{
data: null,
dateRange: 'week',
async loadData() {
this.data = await $wire.callSchemaComponentMethod(
[@js](https://github.com/js)($key),
'getChartData',
{ dateRange: this.dateRange },
)
},
}"
x-init="loadData"
>
<select x-model="dateRange" x-on:change="loadData">
<option value="week">This Week</option>
<option value="month">This Month</option>
<option value="year">This Year</option>
</select>
<template x-if="data">
{{-- Render the chart using the data --}}
</template>
</div>
By default, calling an exposed method will trigger a re-render of the Livewire component. If your method doesn't need to update the UI, you may add Livewire's #[Renderless] attribute alongside #[ExposedLivewireMethod] to skip the re-render:
use Filament\Schemas\Components\Component;
use Filament\Support\Components\Attributes\ExposedLivewireMethod;
use Livewire\Attributes\Renderless;
class Chart extends Component
{
protected string $view = 'filament.schemas.components.chart';
public static function make(): static
{
return app(static::class);
}
#[ExposedLivewireMethod]
#[Renderless]
public function getChartData(): array
{
// ...
}
}
How can I help you explore Laravel packages today?