Filament v4 Unified Schema API: Forms &amp; Infolists | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API

 Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API
======================================================================

 Filament v4 replaces scattered form/infolist component trees with a single Schema API. Learn how unified schemas reduce duplication, enable reuse, and change how you build admin panels.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 2 Aug 2026 · Updated 2 Aug 2026 · 3 min read

ShareCopy linkCopied

 ![Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API](https://cdn.msaied.com/501/98f4034a9cdbe0ac34480781384b9615.png) 

  On this page +1. [Why Filament v4 Rethinks the Component Tree](#why-filament-v4-rethinks-the-component-tree)
2. [The Schema Entry Point](#the-schema-entry-point)
3. [Explicit Infolist Overrides](#explicit-infolist-overrides)
4. [Extracting Reusable Schema Fragments](#extracting-reusable-schema-fragments)
5. [Conditional Visibility Without Duplication](#conditional-visibility-without-duplication)
6. [Testing the Unified Schema](#testing-the-unified-schema)
7. [Key Takeaways](#key-takeaways)

 Why Filament v4 Rethinks the Component Tree
-------------------------------------------

Filament v3 kept forms and infolists as parallel but separate hierarchies. You defined `form(Form $form)` and `infolist(Infolist $infolist)` independently, duplicating field definitions whenever you wanted a read-only view alongside an editable one. Filament v4 collapses this into a **unified Schema API**: one component tree that can render in both contexts.

This is not a cosmetic change. It affects how you structure resources, build reusable field sets, and test panel behaviour.

---

The Schema Entry Point
----------------------

In v4, `Resource` classes expose a `schema()` method that returns a `Schema` instance. Both the form and the infolist delegate to it:

```php
use Filament\Schemas\Schema;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\DatePicker;
use Filament\Infolists\Components\TextEntry;

public static function schema(Schema $schema): Schema
{
    return $schema->components([
        TextInput::make('name')
            ->required()
            ->maxLength(255),

        DatePicker::make('published_at')
            ->nullable(),
    ]);
}

```

Filament resolves whether it is rendering a form or an infolist and maps components accordingly. `TextInput` in a form context becomes a `TextEntry` in an infolist context unless you override it explicitly.

---

Explicit Infolist Overrides
---------------------------

Automatic mapping covers the common cases, but you will sometimes need a richer read-only presentation. Use `->infolistComponent()` on any schema component to swap it out:

```php
use Filament\Infolists\Components\ImageEntry;

TextInput::make('avatar_url')
    ->label('Avatar URL')
    ->url()
    ->infolistComponent(
        ImageEntry::make('avatar_url')->circular()
    ),

```

The form still renders a URL input; the infolist renders a circular image. One definition, two presentations.

---

Extracting Reusable Schema Fragments
------------------------------------

The real productivity gain is extracting shared fragments into plain classes:

```php
namespace App\Filament\Schemas;

use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;

final class AuthorSchema
{
    public static function components(): array
    {
        return [
            Section::make('Author')
                ->columns(2)
                ->schema([
                    TextInput::make('author_name')->required(),
                    Textarea::make('author_bio')->columnSpanFull(),
                ]),
        ];
    }
}

```

Then spread it into any resource schema:

```php
return $schema->components([
    ...AuthorSchema::components(),
    TextInput::make('title')->required(),
]);

```

No trait magic, no inheritance — just plain PHP arrays.

---

Conditional Visibility Without Duplication
------------------------------------------

Schema components carry `->visibleOn()` and `->hiddenOn()` helpers that accept context strings (`'form'`, `'infolist'`, or custom panel identifiers):

```php
TextInput::make('internal_notes')
    ->hiddenOn('infolist'),

TextEntry::make('audit_log')
    ->visibleOn('infolist'),

```

This lets you keep a single schema while still surfacing fields that only make sense in one context.

---

Testing the Unified Schema
--------------------------

Pest assertions work against the resolved context. Use `livewire()` to target the specific page class:

```php
use App\Filament\Resources\PostResource\Pages\EditPost;

it('validates required fields on edit', function () {
    $post = Post::factory()->create();

    livewire(EditPost::class, ['record' => $post->getRouteKey()])
        ->fillForm(['title' => ''])
        ->call('save')
        ->assertHasFormErrors(['title' => 'required']);
});

```

For infolist assertions, target the `ViewPost` page and assert entries are visible:

```php
use App\Filament\Resources\PostResource\Pages\ViewPost;

it('shows author name in infolist', function () {
    $post = Post::factory()->create(['author_name' => 'Ada Lovelace']);

    livewire(ViewPost::class, ['record' => $post->getRouteKey()])
        ->assertSeeText('Ada Lovelace');
});

```

---

Key Takeaways
-------------

- **One schema, two contexts**: v4's unified Schema API eliminates the form/infolist duplication that plagued v3 resources.
- **Automatic component mapping** handles the common cases; `->infolistComponent()` handles the rest.
- **Fragment classes** are the idiomatic way to share schema sections across resources — no traits needed.
- **`->visibleOn()` / `->hiddenOn()`** give per-context visibility without splitting the schema.
- **Pest tests** target page classes directly; form and infolist assertions remain distinct even though the schema is shared.

- [filament](https://www.msaied.com/public/articles?search=filament)
- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [filament-v4](https://www.msaied.com/public/articles?search=filament-v4)
- [admin-panels](https://www.msaied.com/public/articles?search=admin-panels)

 Frequently asked questions 
---------------------------

  Does the unified Schema API mean I can no longer customise the infolist independently?No. You can still override individual components with `-&gt;infolistComponent()` and control visibility per context with `-&gt;visibleOn()` / `-&gt;hiddenOn()`. The unified API reduces duplication for the common case while preserving full control when you need it.

   Are Filament v3 form and infolist definitions still valid in v4?Filament v4 ships compatibility shims for the separate `form()` and `infolist()` methods, but they are deprecated. The recommended migration path is to consolidate into a single `schema()` method and use context helpers for any divergence.

   How do I share a schema fragment between a CreatePost and EditPost page?Extract the shared components into a static method on a plain PHP class (e.g. `PostSchema::components()`) and spread the array into each resource's `schema()` call. No base class or trait is required.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleLaravel Telescope Alternatives: Building a Lightweight Debug Bar with Custom Watchers](https://www.msaied.com/public/articles/laravel-telescope-alternatives-building-a-lightweight-debug-bar-with-custom-watchers-1) [Next articleLaravel Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right](https://www.msaied.com/public/articles/laravel-filament-v3-custom-actions-bulk-table-and-header-actions-done-right)  

   On this page
-------------

1. [Why Filament v4 Rethinks the Component Tree](#why-filament-v4-rethinks-the-component-tree)
2. [The Schema Entry Point](#the-schema-entry-point)
3. [Explicit Infolist Overrides](#explicit-infolist-overrides)
4. [Extracting Reusable Schema Fragments](#extracting-reusable-schema-fragments)
5. [Conditional Visibility Without Duplication](#conditional-visibility-without-duplication)
6. [Testing the Unified Schema](#testing-the-unified-schema)
7. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
