matheusmarnt/ghostwire

Automatic runtime skeleton loaders for Livewire — synthesized from your live DOM, zero markup.
39
Install
composer require matheusmarnt/ghostwire
Latest Version:v1.3.0
PHP:^8.2
License:MIT
Last Updated:Sep 22, 2026
Links: GitHub  ·  Packagist
Maintainer: matheusmarnt

Ghostwire

Automatic runtime skeleton loaders for Livewire — synthesized from your live DOM, zero markup.

📘 Documentation: https://matheusmarnt.github.io/ghostwire/ · 🇧🇷 Português · 🇪🇸 Español

Add wire:ghost to any element (or #[Ghost] to a component class, with zero view changes) and Ghostwire synthesizes a matching skeleton from the live DOM the instant a Livewire request starts — no hand-written placeholder markup, no layout shift, and it works identically whether your app runs Livewire 3.6+ or 4.x.

Features

  • Zero-markup synthesis — walks the live DOM, classifies text/heading/media/control/container/panel nodes, and emits a matching Bone Tree, all in one batched read pass (no forced reflow)
  • Dual Livewire bridge — Livewire 3.6+ and 4.x supported from the same package, selected by runtime feature detection (never a version-string check)
  • Morph-safe — the Ghost Layer mounts outside Livewire's reconciled tree; concealment uses only visibility/opacity/pointer-events, never a structural DOM change
  • freeze mode — dims and disables the live host in place, for layouts synthesis can't safely cover
  • #[Ghost] attribute — class- or method-level, a 7-level precedence cascade (directive modifier → directive expression → method → class → inherited → config → package default), zero view changes required
  • Silence by default — sync-only and polling messages never trigger a ghost, so background updates stay invisible
  • Repeat-sibling sampling, scrollable clipping, sticky/fixed geometry — real layouts (paginated tables, kanban boards, scrollable panels) synthesize correctly, not just simple cards
  • Theming — shimmer/pulse/wave animations, automatic dark mode, prefers-reduced-motion support, all pure CSS behind data/CSS-variable tokens
  • Accessibilityaria-busy, focus preservation across the ghost window, a shared live region announcing loading/idle state; axe-core clean at the strictest level
  • CSP-safe — runs under a strict Content-Security-Policy (no inline scripts, no eval); stylesheet nonce support built in
  • php artisan ghost:inspect — see exactly which precedence level decided each component's configuration
  • php artisan ghost:install — publish assets and get a printed reminder of the two required layout directives in one step
  • Learning — remembers a component's synthesized skeleton locally (opt-in, refused in production) so a lazy-loaded component's first paint on a later visit already has a matching placeholder — export it with php artisan ghost:export as a static Blade @placeholder

Requirements & compatibility

Supported
PHP 8.2, 8.3, 8.4
Laravel 12.x, 13.x
Livewire 3.6+, 4.x

Tier matrix (FR-81)

Bridge selection is runtime feature detection, never a version string. Everything below is verified on both lines in CI.

Tier Capabilities
A — identical Directive + every modifier including .panels, except .island · #[Ghost] in full (class, method, inheritance, precedence) · synthesis · freeze · timing (delay/hold) · sync silence · theme & tokens · accessibility · panels detection and promotion · morph coexistence
B — degraded on 3.x Post-paint removal (emulated via double requestAnimationFrame) · finalization (composed from multiple hooks) · cancellation (resolved as finalization) · poll detection (origin heuristic) · per-action interception (bridge-level filter — same observable behavior)
C — 4.x only Island scoping (.island) · message-skip handling

Full detail: /docs/compat.

Installation

composer require matheusmarnt/ghostwire
php artisan vendor:publish --tag=ghostwire-assets

Add both directives to your main layout, once — usually right next to @livewireStyles/@livewireScripts:

{{-- in <head> --}}
@ghostwireStyles

{{-- right before </body> --}}
@ghostwireScripts

Then add wire:ghost to any element inside a Livewire component:

<div wire:ghost>
    {{-- your existing Livewire markup, unchanged --}}
</div>

Without both the asset publish step and the two directives above, wire:ghost is dead markup — the runtime JS that watches for it never loads. php artisan ghost:install runs the publish step and prints this same reminder for you.

See /docs/install for the full first-effect walkthrough, and /playground to try synthesis on your own markup without installing anything.

Learning

Ghostwire can remember a component's synthesized skeleton locally in the browser and reuse it the next time that component is about to lazy-load — so a later visit's first lazy paint already has a matching skeleton, not a blank placeholder. Off by default, and refused server-side in production regardless of config.

The flag only enables skeleton capture and produces no visible effect by itself — pair it with #[Ghost(lazy: true)] on your component (and Livewire's #[Lazy] for the skeleton to show on initial load) to paint the learned skeleton.

GHOSTWIRE_LEARNING=true
#[Ghost(lazy: true)]
class OrdersTable extends Component
{
    // ...
}
Ghostwire.exportLearned()      // in the browser: downloads ghostwire-learned.json
php artisan ghost:export --component=orders-table --breakpoint=lg --from=~/Downloads/ghostwire-learned.json

Full walkthrough, storage/privacy details, and the export command's security posture: /docs/learning.

Documentation

Full docs, live playground, and gallery: https://matheusmarnt.github.io/ghostwire/

Security

See SECURITY.md and /docs/security. No DOM data ever leaves the browser; learning is local-only; zero telemetry (FR-93).

Other packages by the author

License

MIT © Matheus Mariano. See LICENSE.md.

Related Packages

janecodelife/livewire-secure-properties

Automatically lock Livewire properties from client-side modification unless expl...

17 2
fabioguin/livewire-searchable-select

High-performance Livewire component for searchable select inputs with relevance-...

122 1
mrshanebarron/skeleton

Skeleton loading placeholder component for Laravel - supports Livewire and Vue

13 0
laravolt/packer

A cli tool for creating Laravel packages.

2,991 9