Skip to content

#[Ghost] attribute

Apply to a component class — no view changes required:

use Ghostwire\Attributes\Ghost;
#[Ghost(mode: 'synthesize', delay: 200, hold: 400)]
class ProductTable extends Component
{
// ...
}
ParameterTypeDefaultMeaning
mode'synthesize'|'freeze'|'off''synthesize'Loading strategy for this component
onlyarray<string>|nullnullActions that activate the ghost
exceptarray<string>|nullnullActions that never activate it
delayint|nullnull (package default: 120ms)Delay before the ghost appears
holdint|nullnull (package default: 300ms)Minimum visible duration
rowsint|nullnullRepeat-row hint for an empty host
pollboolfalseAllow polled messages to activate the ghost
syncboolfalseAllow property-only (sync) messages to activate it
lazyboolfalseReuse the learned tree as the lazy placeholder
panelsboolfalsePromote visually distinct containers to their own panel bone

Action filtering — restrict or exclude specific actions from the class-level config:

#[Ghost(only: ['loadMore', 'applyFilters'])]
class ProductList extends Component
{
// ...
}

Only loadMore and applyFilters activate the ghost; every other action leaves it alone.

#[Ghost(except: ['toggleFavorite'])]
class ProductList extends Component
{
// ...
}

Every action activates the ghost except toggleFavorite.

#[Ghost(rows: 5)]
class OrderTable extends Component
{
// ...
}

Renders 5 skeleton rows when the table has no data yet — the attribute equivalent of wire:ghost.rows.5.

#[Ghost(poll: true)]
class LiveTicker extends Component
{
// ...
}

Lets a wire:poll-driven refresh activate the ghost too; polled messages are silent by default.

#[Ghost(sync: true)]
class SearchResults extends Component
{
// ...
}

Lets a property-only update (e.g. wire:model.live) activate the ghost too; sync messages are silent by default.

#[Ghost(lazy: true)]
class Dashboard extends Component
{
// ...
}

Reuses a previously learned Bone Tree as the lazy-loading placeholder — see Learning for the full setup.

#[Ghost(panels: true)]
class ProductGrid extends Component
{
// ...
}

Cards with a visible background, border, or shadow each get their own filled panel bone — see How it works.

Seven levels, most to least specific:

  1. Directive modifier on the element — e.g. wire:ghost.freeze
  2. Directive expression / action targeting — e.g. wire:ghost="applyFilters"
  3. #[Ghost] on the executing action’s method
  4. #[Ghost] on the component class
  5. #[Ghost] inherited from a base class or trait
  6. config/ghostwire.php
  7. Package defaults

The wire:ghost directive on the element outranks the #[Ghost] attribute: a directive-level setting overrides whatever the attribute levels declare, field by field. Any field a given level doesn’t declare falls through to the next. Inspect exactly which level decided a component’s live configuration with:

Terminal window
php artisan ghost:inspect
#[Ghost(mode: 'freeze')]
class ReportTable extends Component
{
#[Ghost(mode: 'synthesize', delay: 50)]
public function refresh() { /* ... */ }
}

refresh()’s own attribute overrides the class-level default for that action only.