Skip to content

Inertia Pages Can Update Themselves Now

Inertia Pages Can Update Themselves Now
taylor otwell shipped live props for inertia. mark a prop, wire a broadcast, stop polling.

Taylor Otwell posted a thread today about new Inertia updates. The headline feature is Live Props.

Mark a prop as live and connect it to a broadcast event. When that event fires, Inertia refreshes just that prop. No polling. Order statuses, unread counts, dashboards. The usual suspects.

return Inertia::render('Orders/Show', [
    'order' => Inertia::live($order, on: new OrderUpdated($order)),
]);

Any event you already broadcast works. No extra config. The event is just a signal. Inertia does a partial reload, so each user still gets whatever the controller resolves for them. Multiple events are fine. Deferred props still work with it.

return Inertia::render('Orders/Show', [
    'order' => Inertia::live(fn () => $order, on: [
        new OrderUpdated($order),
        new OrderShipped($order),
    ]),
'metrics' => Inertia::defer(fn () => $order->metrics())
    ->live(on: new OrderUpdated($order)),

]);

On the client, you tell createInertiaApp() how to listen. Built-in support for Laravel Echo (Reverb, Pusher, and friends), pusher-js, and Action Cable for Rails. Inertia reads subscriptions from each page's props, so navigating subscribes and unsubscribes for you.

import { createInertiaApp } from '@inertiajs/vue3'
import { echo } from '@inertiajs/vue3/echo'
import { configureEcho } from '@laravel/echo-vue'

configureEcho({ broadcaster: 'reverb', })

createInertiaApp({ live: echo(), })

Got a dashboard open in a thousand tabs? An event can carry the new values with it through Inertia::broadcastProps(), so pages update without making a request. Useful when the data is the same for everyone on the channel.

class OrderUpdated implements ShouldBroadcast
{
public function __construct(public Order $order) {}

public function broadcastOn(): PrivateChannel
{
    return new PrivateChannel("orders.{$this->order->id}");
}

public function broadcastWith(): array
{
    return Inertia::broadcastProps([
        'order' => OrderResource::make($this->order),
    ]);
}

}

Live Props are polite about the server too. Each prop refreshes at most once per second, a burst of events from one action becomes a single request, and background tabs wait until the user comes back. Throttle is tunable per app or per prop.

return Inertia::render('Dashboard', [
'metrics' => Inertia::live(
value: Metrics::today(),
on: MetricsUpdated::class,
throttle: 5000
),
]);

There's a new useProp() helper with a loading flag for a subtle loading state.

<script setup>
import { useProp } from '@inertiajs/vue3'

defineProps({ order: Object })

const { loading } = useProp('order') </script>

<template> <div :class="{ 'opacity-50': loading }"> {{ order.status }} </div> </template>

Rather not shove new data under the user? Return false from the live event listener and show a "New data available" button instead.

import { router } from '@inertiajs/vue3'

router.on('live', (event) => { showNewDataBanner(event.detail.props)

return false })

A few other updates came with it.

Inertia supports the QUERY HTTP method. Like GET for fetching, but the data goes in the body, so large nested search filters don't get crammed into the URL.

<script setup>
import { Link, router } from '@inertiajs/vue3'

const search = () => router.query('/products', { categories: ['Keyboards', 'Monitors'], price: { min: 100, max: 500 }, }) </script>

<template> <button @click="search">Search</button>

<Link href="/products" method="query" :data="{ brand: 'Acme' }"> Acme products </Link> </template>

Polling has a background option. Set it to pause and it stops while the tab is hidden. When the user returns, Inertia only sends a request if one was due.

import { usePoll } from '@inertiajs/vue3'

usePoll(5000, {}, { background: 'pause' })

The navigate event now says how the user arrived: initial load, regular visit, or back/forward. Handy for refreshing stale props after a history restore.

import { router } from '@inertiajs/vue3'

router.on('navigate', (event) => { if (event.detail.type === 'history') { router.reload({ only: ['messages'] }) } })

inertia:start-ssr has a --no-stop-before-start option, so starting a new SSR server won't shut down one that's already running.

Real-time pages without a custom websocket layer for every widget. That's the useful part. The boring throttles and the "don't update under the user" escape hatch are what make it shippable.

Khaled Nadam

Khaled Nadam

Software engineer & technical writer

I write about software development, web technologies, and my experiences in the tech industry. I love building products that help people.