Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Live Preview Laravel Package

wotz/filament-live-preview

Filament Live Preview brings real-time previewing to Filament forms and resources, letting editors see changes as they type before saving. Easy to install and configure, it helps content teams catch layout and copy issues early, cutting down on publish-time surprises.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a single-purpose Filament plugin: it gives your Resource/Page a preview button that renders your actual front-end with the current, unsaved form state. There is no database footprint — the whole value is "see the page before you hit Save." At 0 stars and 0 dependents, treat the source as the documentation; read src/ before you wire it in.

Install and register

composer require wotz/filament-live-preview
php artisan vendor:publish --tag="filament-live-preview-config"   # if the tag exists
// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(\Wotz\FilamentLivePreview\LivePreviewPlugin::make());
}

Class/config names above follow the package's naming convention — confirm them against src/ and the config file after publishing, because at this maturity there is no tutorial corpus to fall back on.

Where to look first, in order

  1. The published config — it will tell you the route prefix, middleware stack, and which models/pages are allowed to preview. This is the file you will actually edit.
  2. php artisan route:list | grep -i preview — confirm the preview route exists, what middleware protects it, and whether it is GET or POST.
  3. The action/page classes in src/ — this is what you attach to a Resource.
  4. Your own front-end route that the preview renders. The plugin does not render your site; you point it at a route you already have.

First use case

A PostResource with a rich-text body and a hero image. Open the edit page, change the title and body without saving, click Preview, and get your real posts.show Blade view in a new tab/iframe showing the draft copy. That is the whole loop — everything else is configuration of how the payload reaches that view.

Implementation Patterns

Wire the preview URL to an existing front-end route. The plugin needs a closure that maps form state to a URL. The cleanest pattern is a dedicated, auth-protected preview route that reuses your production Blade view, rather than trying to reuse the public route with a magic query string:

// routes/web.php
Route::middleware(['web', 'auth'])
    ->get('/preview/posts/{token}', [PostPreviewController::class, 'show'])
    ->name('posts.preview');

The form serializes its state to a cache/session keyed by $token; the preview controller pulls it back out, hydrates a non-persisted model, and returns view('posts.show', ['post' => $post]). This keeps the payload out of the URL and sidesteps POST-size limits on long rich-text bodies.

Hydrate, don't save. The single most important pattern:

$post = new Post();
$post->fill($payload);        // no save(), no update()
$post->id = $payload['id'] ?? null;  // keep route generation working
return view('posts.show', compact('post'));

Fill a fresh instance (or Post::newModelInstance()), never findOrFail()->fill()->save(). Observers, updated events, and revision tables must not fire from a preview.

Attach it as a header action on create and edit pages. Previewing an unsaved draft is the primary use case, so the create page matters more than the edit page. If the plugin only ships a Page class, you can also call it from a Action::make('preview')->action(...) in getHeaderActions().

Pass through everything the view reads. Locale, currency, tenant, related-model picks from a Select, repeater rows — if your front-end view touches it, it must be in the payload. Write one toPreviewPayload() method on the form/page and use it in both create and edit contexts so the two never drift.

Repeaters and relations need explicit handling: map repeater state to unsaved related models ($post->setRelation('blocks', $blocks)) instead of relying on lazy-loading from the DB, or your preview will silently show the saved blocks.

If your front-end is Livewire/Inertia, an iframe pointing at the preview route is more reliable than trying to swap props in place. Inertia in particular will not re-render on iframe-less prop changes without a full visit.

Gotchas and Tips

Temp uploads will 403 or 404. Filament stores TemporaryUploadedFiles on the tmp disk under a session-scoped path. A preview request in a different request cycle — especially inside an iframe — may not have the same session, so image URLs break. Either copy temp files into a preview-accessible disk on save of the preview action, or fall back to the persisted image when $file is temporary.

Session/CSRF is the usual failure mode. If the preview is a POST from an iframe, you need the CSRF token in the payload. The most robust pattern is: Livewire action writes payload to cache → returns a redirect/URL → iframe does a plain GET. Avoid POSTing form data directly from an iframe.

Route model binding will betray you. Route::get('/preview/posts/{post}') binds the persisted record, so you preview stale data and never notice. Use an opaque token, not a model key.

Don't let the preview route be public. It renders unpublished content and, if you hydrate from an arbitrary payload, can be an information-disclosure vector. auth + a policy check on the underlying record is the minimum. Also exclude it from any HTTP cache / CDN.

Disable response caching for preview responses (Cache-Control: no-store). A cached preview is worse than no preview because it looks correct.

Pin the version. Zero dependents and a 2026 release date mean the API can move under you. "wotz/filament-live-preview": "1.0.x" in composer.json, and commit the lockfile. Check the Filament major it targets against yours before installing — Filament 3 vs 4 action APIs are not interchangeable.

Expect thin docs; budget for a fork. Clone the repo and read the action class end to end. If the preview URL closure isn't exposed publicly, fork and add it rather than fighting it — the package is small enough that a fork is cheaper than a workaround.

Debugging checklist: route:list for the preview route → browser Network tab for the iframe request status → Log::info($payload) at the top of the preview controller → confirm the view renders with a persisted model first, then re-test with the payload. If the view works saved but not previewed, it's a missing key in the payload, not a plugin bug.

Extension points to lean on: publish and override the preview Blade view so the iframe gets your real layout and assets; the config's middleware array is the right place to add tenant scoping (InitializeTenancyByDomain) if your front-end is multi-tenant.

Skip it if you only need to preview a couple of fields, or your front-end already has a draft/preview token system — in that case a 30-line custom Filament action calling your existing preview endpoint is less risk than an unmaintained dependency.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin