Skip to main content

Using schema and table classes

Since many Filament methods define both the UI and the functionality of the app in just one method, it can be easy to end up with giant methods and files. These can be difficult to read, even if your code has a clean and consistent style. Filament tries to mitigate some of this by providing dedicated schema and table classes when you generate a resource. These classes have a configure() method that accepts a $schema or $table. You can then call the configure() method from anywhere you want to define a schema or table. For example, if you have the following app/Filament/Resources/Customers/Schemas/CustomerForm.php file:
You can use this in the form() method of the resource:
You could do the same for the table():
Or the infolist():
These schema and table classes deliberately don’t have a parent class or interface by default. If Filament were to enforce a method signature for the configure() method, you would not be able to pass your own configuration variables to the method, which could be useful if you wanted to reuse the same class in multiple places but with slight tweaks.

Using component classes

Even if you are using schema and table classes to keep the schema and table definitions in their own files, you can still end up with a very long configure() method. This is especially true if you are using a lot of components in your schema or table, or if the components require a lot of configuration. You can mitigate this by creating dedicated classes for each component. For example, if you have a TextInput component that requires a lot of configuration, you can create a dedicated class for it:
You can then use this class in your schema or table:
You could do this with a number of different types of component. There are no enforced rules as to how these components should be named or where they should be stored. However, here are some ideas:
  • Schema components: These could live in the Schemas/Components directory of the resource. They could be named after the component they are wrapping, for example CustomerNameInput or CustomerCountrySelect.
  • Table columns: These could live in the Tables/Columns directory of the resource. They could be named after the column followed by Column, for example CustomerNameColumn or CustomerCountryColumn.
  • Table filters: These could live in the Tables/Filters directory of the resource. They could be named after the filter followed by Filter, for example CustomerCountryFilter or CustomerStatusFilter.
  • Actions: These could live in the Actions directory of the resource. They could be named after the action followed by Action or BulkAction, for example EmailCustomerAction or UpdateCustomerCountryBulkAction.
As a further example, here is a potential EmailCustomerAction class:
And you could use it in the getHeaderActions() of a page:
Or you could use it on a table row: