Download as pdf or txt
Download as pdf or txt
You are on page 1of 138

3/25/24, 9:59 AM inertiajs/inertia-django: The Django adapter for Inertia.

js

inertiajs /
inertia-django

Code Issues 10 Pull requests 4 Actions Projects Security Insights

The Django adapter for Inertia.js

MIT license

217 stars 22 forks 6 watching 1 Branch 0 Tags Activity Custom properties

Public repository

main 1 Branch 0 Tags Go to file t Go to file Add file Code

BrandonShar bump to 0.6.0 2 months ago

inertia Fixed 303 redirect for PUT method (#27) 6 months ago

.gitignore test, test, test 2 years ago

CHANGELOG.md bump to 0.6.0 2 months ago

LICENSE initial commit 2 years ago

README.md Add examples to Readme, add Django Svelte Te… 3 months ago

pyproject.toml bump to 0.6.0 2 months ago

pytest.ini test, test, test 2 years ago

setup.cfg initial commit 2 years ago

README MIT license

Inertia.js Django Adapter

Installation

Backend
Install the following python package via pip

pip install inertia-django

Add the Inertia app to your INSTALLED_APPS in settings.py

INSTALLED_APPS = [
# django apps,
'inertia',

https://github.com/inertiajs/inertia-django?tab=readme-ov-file 1/5
3/25/24, 9:59 AM inertiajs/inertia-django: The Django adapter for Inertia.js
# your project's apps,
]

Add the Inertia middleware to your MIDDLEWARE in settings.py

MIDDLEWARE = [
# django middleware,
'inertia.middleware.InertiaMiddleware',
# your project's middleware,
]

Finally, create a layout which exposes {% block inertia %}{% endblock %} in the body and set the path to this layout as INERTIA_LAYOUT in
your settings.py file.

Now you're all set!

Frontend
Django specific frontend docs coming soon. For now, we recommend installing django_vite and following the commits on the Django Vite
example repo. Once Vite is setup with your frontend of choice, just replace the contents of entry.js with this file (example in react)

You can also check out the official Inertia docs at https://inertiajs.com/.

CSRF
Django's CSRF tokens are tightly coupled with rendering templates so Inertia Django automatically handles adding the CSRF cookie for you to
each Inertia response. Because the default names Django users for the CSRF headers don't match Axios (the Javascript request library Inertia
uses), we'll need to either modify Axios's defaults OR Django's settings.

You only need to choose one of the following options, just pick whichever makes the most sense to you!

In your entry.js file

axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = "csrftoken"

OR

In your Django settings.py file

CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'
CSRF_COOKIE_NAME = 'XSRF-TOKEN'

Usage

Responses
Render Inertia responses is simple, you can either use the provided inertia render function or, for the most common use case, the inertia
decorator. The render function accepts four arguments, the first is your request object. The second is the name of the component you want to
render from within your pages directory (without extension). The third argument is a dict of props that should be provided to your
components. The final argument is template_data , for any variables you want to provide to your template, but this is much less common.

from inertia import render


from .models import Event

def index(request):
return render(request, 'Event/Index', props={
'events': Event.objects.all()
})

Or use the simpler decorator for the most common use cases

https://github.com/inertiajs/inertia-django?tab=readme-ov-file 2/5
3/25/24, 9:59 AM inertiajs/inertia-django: The Django adapter for Inertia.js

from inertia import inertia


from .models import Event

@inertia('Event/Index')
def index(request):
return {
'events': Event.objects.all(),
}

Shared Data
If you have data that you want to be provided as a prop to every component (a common use-case is information about the authenticated user)
you can use the share method. A common place to put this would be in some custom middleware.

from inertia import share


from django.conf import settings
from .models import User

def inertia_share(get_response):
def middleware(request):
share(request,
app_name=settings.APP_NAME,
user_count=lambda: User.objects.count(), # evaluated lazily at render time
user=lambda: request.user, # evaluated lazily at render time
)

return get_response(request)
return middleware

Lazy Props
On the front end, Inertia supports the concept of "partial reloads" where only the props requested are returned by the server. Sometimes, you
may want to use this flow to avoid processing a particularly slow prop on the intial load. In this case, you can use Lazy props . Lazy props aren't
evaluated unless they're specifically requested by name in a partial reload.

from inertia import lazy, inertia

@inertia('ExampleComponent')
def example(request):
return {
'name': lambda: 'Brandon', # this will be rendered on the first load as usual
'data': lazy(lambda: some_long_calculation()), # this will only be run when specifically requested by partial props and WILL
}

Json Encoding
Inertia Django ships with a custom JsonEncoder at inertia.utils.InertiaJsonEncoder that extends Django's DjangoJSONEncoder with
additional logic to handle encoding models and Querysets. If you have other json encoding logic you'd prefer, you can set a new JsonEncoder
via the settings.

SSR

Backend

Enable SSR via the INERTIA_SSR_URL and INERTIA_SSR_ENABLED settings

Frontend

Coming Soon!

https://github.com/inertiajs/inertia-django?tab=readme-ov-file 3/5
3/25/24, 9:59 AM inertiajs/inertia-django: The Django adapter for Inertia.js

Settings
Inertia Django has a few different settings options that can be set from within your project's settings.py file. Some of them have defaults.

The default config is shown below

INERTIA_VERSION = '1.0' # defaults to '1.0'


INERTIA_LAYOUT = 'layout.html' # required and has no default
INERTIA_JSON_ENCODER = CustomJsonEncoder # defaults to inertia.utils.InertiaJsonEncoder
INERTIA_SSR_URL = 'http://localhost:13714' # defaults to http://localhost:13714
INERTIA_SSR_ENABLED = False # defaults to False

Testing
Inertia Django ships with a custom TestCase to give you some nice helper methods and assertions. To use it, just make sure your TestCase
inherits from InertiaTestCase . InertiaTestCase inherits from Django's django.test.TestCase so it includes transaction support and a client.

from inertia.test import InertiaTestCase

class ExampleTestCase(InertiaTestCase):
def test_show_assertions(self):
self.client.get('/events/')

# check the component


self.assertComponentUsed('Event/Index')

# access the component name


self.assertEqual(self.component(), 'Event/Index')

# props (including shared props)


self.assertHasExactProps({name: 'Brandon', sport: 'hockey'})
self.assertIncludesProps({sport: 'hockey'})

# access props
self.assertEquals(self.props()['name'], 'Brandon')

# template data
self.assertHasExactTemplateData({name: 'Brian', sport: 'basketball'})
self.assertIncludesTemplateData({sport: 'basketball'})

# access template data


self.assertEquals(self.template_data()['name'], 'Brian')

The inertia test helper also includes a special inertia client that pre-sets the inertia headers for you to simulate an inertia response. You can
access and use it just like the normal client with commands like self.inertia.get('/events/') . When using the inertia client, inertia custom
assertions are not enabled though, so only use it if you want to directly assert against the json response.

Examples

Django Svelte Template - A Django template and example project demonstrating Inertia with Svelte and SSR.

Thank you
A huge thank you to the community members who have worked on InertiaJS for Django before us. Parts of this repo were particularly inspired
by Andres Vargas and Samuel Girardin. Additional thanks to Andres for the Pypi project.

Maintained and sponsored by the team at bellaWatt

https://github.com/inertiajs/inertia-django?tab=readme-ov-file 4/5
3/25/24, 9:59 AM inertiajs/inertia-django: The Django adapter for Inertia.js

Releases

No releases published

Packages

No packages published

Contributors 8

Languages

Python 98.0% HTML 2.0%

https://github.com/inertiajs/inertia-django?tab=readme-ov-file 5/5
3/25/24, 10:17 AM Demo application - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Demo application

We've setup a demo app for Inertia.js called Ping CRM. This application is built
using Laravel and Vue. You can find the source code on GitHub.

The Ping CRM demo is hosted on Heroku and the database is reset every hour. Please
be respectful when editing data.

https://inertiajs.com/demo-application 1/2
3/25/24, 10:17 AM Demo application - Inertia.js

In addition to the Vue version of Ping CRM, we also maintain a Svelte version of the
application, which you can find on GitHub.

Third party

Beyond our official demo app, Ping CRM has also been translated into numerous
different languages and frameworks.

Ruby on Rails/Vue by Georg Ledermann


Laravel/React by Lado Lomidze
Laravel/Svelte by Zura Gabievi
Laravel/Mithril.js by Thomas Breuss
Yii 2/Vue by Thomas Breuss
Symfony/Vue by Aleks Seltenreich
Clojure/React by Michaël Salihi

https://inertiajs.com/demo-application 2/2
3/25/24, 10:18 AM Upgrade guide - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Upgrade guide

Inertia.js v1.0 has been released! 🥳

What's new

This release focuses on simplifying the overall architecture of the project with the
goal of making Inertia easier to maintain and easier to use.

It includes a number of breaking changes, mostly related to package names and


updated named exports. This guide explains how to upgrade your project to v1.0.

For a complete list of all the changes, see the release notes.

New dependencies

To use previous Inertia releases, you had to install a number of libraries, including
the core library ( @inertiajs/inertia ), the adapter of your choice
( @inertiajs/inertia-vue|vue3|react|svelte ), the progress library ( @inertiajs/progress ),
and if you were using server-side rendering, the server library ( @inertiajs/server ).

https://inertiajs.com/upgrade-guide 1/6
3/25/24, 10:18 AM Upgrade guide - Inertia.js

Moving forward you are now only required to install a single library — the adapter
of your choice (Vue, React, or Svelte), and all other core libraries are automatically
installed for you.

To get started, remove all of the old Inertia libraries.

Vue 2 Vue 3 React Svelte

npm remove @inertiajs/inertia @inertiajs/inertia-vue3 @inertiajs/progress @inertiajs/ser

Next, install the new Inertia adapter of your choice. The new adapter libraries have
been renamed, and no longer include inertia- in them.

Vue 2 Vue 3 React Svelte

npm install @inertiajs/vue3

Renamed imports

Next, update all the Inertia related imports in your project to use the new adapter
library name. All imports are now available from the adapter library, meaning you
no longer import anything from the Inertia core library, progress library, or server
library.

Additionally, some exports have been renamed and previously deprecated


exports have been removed. For example, the Inertia export has been renamed
to router .

Here is a complete list of all the import changes:


https://inertiajs.com/upgrade-guide 2/6
3/25/24, 10:18 AM Upgrade guide - Inertia.js

Vue 2 Vue 3 React Svelte

- import { Inertia } from '@inertiajs/inertia'


+ import { router } from '@inertiajs/vue3'

- import createServer from '@inertiajs/server'


+ import createServer from '@inertiajs/vue3/server'

- import { createInertiaApp } from '@inertiajs/inertia-vue3'


- import { App } from '@inertiajs/inertia-vue3'
- import { app } from '@inertiajs/inertia-vue3'
- import { plugin } from '@inertiajs/inertia-vue3'
- import { InertiaApp } from '@inertiajs/inertia-vue3'
+ import { createInertiaApp } from '@inertiajs/vue3'

- import { usePage } from '@inertiajs/inertia-vue3'


+ import { usePage } from '@inertiajs/vue3'

- import { useForm } from '@inertiajs/inertia-vue3'


+ import { useForm } from '@inertiajs/vue3'

- import { useRemember } from '@inertiajs/inertia-vue3'


+ import { useRemember } from '@inertiajs/vue3'

- import { Head } from '@inertiajs/inertia-vue3'


- import { InertiaHead } from '@inertiajs/inertia-vue3'
+ import { Head } from '@inertiajs/vue3'

- import { Link } from '@inertiajs/inertia-vue3'


- import { link } from '@inertiajs/inertia-vue3'
- import { InertiaLink } from '@inertiajs/inertia-vue3'
+ import { Link } from '@inertiajs/vue3'

It is no longer possible to manually configure Inertia using the App export. Instead,
you should use the createInertiaApp() helper. See the client-side setup
documentation for more information.

Progress
https://inertiajs.com/upgrade-guide 3/6
3/25/24, 10:18 AM Upgrade guide - Inertia.js

Previously, the progress indicator was available as a separate plugin


( @inertiajs/progress ). It is now installed and enabled by default.

If you haven't yet, remove the old progress library.

Vue 2 Vue 3 React Svelte

npm remove @inertiajs/progress

Next, remove the InertiaProgress import and InertiaProgress.init() call, as they


are no longer required.

- import { InertiaProgress } from '@inertiajs/progress'

- InertiaProgress.init()

Finally, if you have defined any progress customizations, you can move them to the
progress property of the createInertiaApp() helper.

createInertiaApp({
progress: {
color: '#29d',
},
// ...
})

If you're using a custom progress indicator, you can disable the default progress
indicator by setting the progress property to false .

https://inertiajs.com/upgrade-guide 4/6
3/25/24, 10:18 AM Upgrade guide - Inertia.js

createInertiaApp({
progress: false,
// ...
})

Setup arguments

We've removed the previously deprecated lowercase app argument from the
setup() method in createInertiaApp() . Use App instead.

createInertiaApp({
// ...
- setup({ app, props }) {
+ setup({ App, props }) {
// ...
},
})

Simplified usePage

In the Vue 3 adapter, we simplified the usePage() hook to no longer require adding
.value after the component , props , url and version properties.

If you're using the usePage() hook, remove all instances of .value .

import { computed } from 'vue'

- const appName = computed(() => usePage().props.value.appName)


+ const appName = computed(() => usePage().props.appName)

https://inertiajs.com/upgrade-guide 5/6
3/25/24, 10:18 AM Upgrade guide - Inertia.js

https://inertiajs.com/upgrade-guide 6/6
3/25/24, 10:18 AM Server-side setup - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Server-side setup

The first step when installing Inertia is to configure your server-side framework.
Inertia maintains an official server-side adapter for Laravel. For other frameworks,
please see the community adapters.

Inertia is fine-tuned for Laravel, so the documentation examples on this website


utilize Laravel. For examples of using Inertia with other server-side frameworks,
please refer to the framework specific documentation maintained by that
adapter.

Laravel starter kits

Laravel's starter kits, Breeze and Jetstream, provide out-of-the-box scaffolding for
new Inertia applications. These starter kits are the absolute fastest way to start
building a new Inertia project using Laravel and Vue or React. However, if you
would like to manually install Inertia into your application, please consult the
documentation below.

Install dependencies

https://inertiajs.com/server-side-setup 1/4
3/25/24, 10:18 AM Server-side setup - Inertia.js

First, install the Inertia server-side adapter using the Composer package manager.

composer require inertiajs/inertia-laravel

Root template

Next, setup the root template that will be loaded on the first page visit to your
application. This will be used to load your site assets (CSS and JavaScript), and will
also contain a root <div> in which to boot your JavaScript application.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=
@vite('resources/js/app.js')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>

This template should include your assets, as well as the @inertia and @inertiaHead

directives.

By default, Inertia's Laravel adapter will assume your root template is named
app.blade.php . If you would like to use a different root view, you can change it using
the Inertia::setRootView() method.

https://inertiajs.com/server-side-setup 2/4
3/25/24, 10:18 AM Server-side setup - Inertia.js

Middleware

Next we need to setup the Inertia middleware. You can accomplish this by
publishing the HandleInertiaRequests middleware to your application, which can be
done using the following Artisan command.

php artisan inertia:middleware

Once the middleware has been published, append the HandleInertiaRequests

middleware to the web middleware group in your application's bootstrap/app.php

file.

use App\Http\Middleware\HandleInertiaRequests;

->withMiddleware(function (Middleware $middleware) {


$middleware->web(append: [
HandleInertiaRequests::class,
]);
})

This middleware provides a version() method for setting your asset version, as well
as a share() method for defining shared data.

Creating responses

That's it, you're all ready to go server-side! Now you're ready to start creating
Inertia pages and rendering them via responses.

use Inertia\Inertia;

https://inertiajs.com/server-side-setup 3/4
3/25/24, 10:18 AM Server-side setup - Inertia.js

class EventsController extends Controller


{
public function show(Event $event)
{
return Inertia::render('Event/Show', [
'event' => $event->only(
'id',
'title',
'start_date',
'description'
),
]);
}
}

https://inertiajs.com/server-side-setup 4/4
3/25/24, 10:18 AM Client-side setup - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Client-side setup

Once you have your server-side framework configured, you then need to setup
your client-side framework. Inertia currently provides support for React, Vue, and
Svelte.

Laravel starter kits

Laravel's starter kits, Breeze and Jetstream, provide out-of-the-box scaffolding for
new Inertia applications. These starter kits are the absolute fastest way to start
building a new Inertia project using Laravel and Vue or React. However, if you
would like to manually install Inertia into your application, please consult the
documentation below.

Install dependencies

First, install the Inertia client-side adapter corresponding to your framework of


choice.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/client-side-setup 1/3
3/25/24, 10:18 AM Client-side setup - Inertia.js

npm install @inertiajs/vue3

Initialize the Inertia app

Next, update your main JavaScript file to boot your Inertia app. To accomplish
this, we'll initialize the client-side framework with the base Inertia component.

Vue 2 Vue 3 React Svelte

import { createApp, h } from 'vue'


import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})

The setup callback receives everything necessary to initialize the client-side


framework, including the root Inertia App component.

Resolving components

The resolve callback tells Inertia how to load a page component. It receives a
page name (string), and returns a page component module. How you implement
this callback depends on which bundler (Vite or Webpack) you're using.
https://inertiajs.com/client-side-setup 2/3
3/25/24, 10:18 AM Client-side setup - Inertia.js

Vue 2 Vue 3 React Svelte

// Vite
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},

// Webpack
resolve: name => require(`./Pages/${name}`),

By default we recommend eager loading your components, which will result in a


single JavaScript bundle. However, if you'd like to lazy-load your components, see
our code splitting documentation.

Defining a root element

By default, Inertia assumes that your application's root template has a root
element with an id of app . If your application's root element has a different id ,

you can provide it using the id property.

createInertiaApp({
id: 'my-app',
// ...
})

https://inertiajs.com/client-side-setup 3/3
3/25/24, 10:19 AM Who is Inertia.js for? - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Who is Inertia.js for?

Inertia was crafted for development teams and solo hackers who typically build
server-side rendered applications using frameworks like Laravel, Ruby on Rails, or
Django. You're used to creating controllers, retrieving data from the database (via
an ORM), and rendering views.

But what happens when you want to replace your server-side rendered views with
a modern, JavaScript-based single-page application frontend? The answer is
always "you need to build an API". Because that's how modern SPAs are built.

This means building a REST or GraphQL API. It means figuring out authentication
and authorization for that API. It means client-side state management. It means
setting up a new Git repository. It means a more complicated deployment
strategy. And this list goes on. It's a complete paradigm shift, and often a
complete mess. We think there is a better way.

Inertia empowers you to build a modern, JavaScript-based single-page


application without the tiresome complexity.

Inertia works just like a classic server-side rendered application. You create
controllers, you get data from the database (via your ORM), and you render views.
But, Inertia views are JavaScript page components written in React, Vue, or Svelte.

https://inertiajs.com/who-is-it-for 1/2
3/25/24, 10:19 AM Who is Inertia.js for? - Inertia.js

This means you get all the power of a client-side application and modern SPA
experience, but you don't need to build an API. We think it's a breath of fresh air
that will supercharge your productivity.

https://inertiajs.com/who-is-it-for 2/2
3/25/24, 10:19 AM How it works - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

How it works

With Inertia you build applications just like you've always done with your server-
side web framework of choice. You use your framework's existing functionality for
routing, controllers, middleware, authentication, authorization, data fetching, and
more.

However, Inertia replaces your application's view layer. Instead of using server-side
rendering via PHP or Ruby templates, the views returned by your application are
JavaScript page components. This allows you to build your entire frontend using
React, Vue, or Svelte, while still enjoying the productivity of Laravel or your
preferred server-side framework.

As you might expect, simply creating your frontend in JavaScript doesn't give you
a single-page application experience. If you were to click a link, your browser
would make a full page visit, which would then cause your client-side framework
to reboot on the subsequent page load. This is where Inertia changes everything.

At its core, Inertia is essentially a client-side routing library. It allows you to make
page visits without forcing a full page reload. This is done using the <Link>

component, a light-weight wrapper around a normal anchor link. When you click
an Inertia link, Inertia intercepts the click and makes the visit via XHR instead. You
can even make these visits programmatically in JavaScript using router.visit() .

https://inertiajs.com/how-it-works 1/2
3/25/24, 10:19 AM How it works - Inertia.js

When Inertia makes an XHR visit, the server detects that it's an Inertia visit and,
instead of returning a full HTML response, it returns a JSON response with the
JavaScript page component name and data (props). Inertia then dynamically
swaps out the previous page component with the new page component and
updates the browser's history state.

The end result is a silky smooth single-page experience. 🎉

To learn more about the nitty-gritty, technical details of how Inertia works under
the hood, check out the protocol page.

https://inertiajs.com/how-it-works 2/2
3/25/24, 10:19 AM The protocol - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

The protocol

This page contains a detailed specification of the Inertia protocol. Be sure to read
the how it works page first for a high-level overview.

HTML responses

The very first request to an Inertia app is just a regular, full-page browser request,
with no special Inertia headers or data. For these requests, the server returns a full
HTML document.

This HTML response includes the site assets (CSS, JavaScript) as well as a root
<div> in the page's body. The root <div> serves as a mounting point for the client-
side app, and includes a data-page attribute with a JSON encoded page object
for the initial page. Inertia uses this information to boot your client-side framework
and display the initial page component.

REQUEST

GET: http://example.com/events/80
Accept: text/html, application/xhtml+xml

RESPONSE

HTTP/1.1 200 OK

https://inertiajs.com/the-protocol 1/6
3/25/24, 10:19 AM The protocol - Inertia.js

Content-Type: text/html; charset=utf-8

<html>
<head>
<title>My app</title>
<link href="/css/app.css" rel="stylesheet">
<script src="/js/app.js" defer></script>
</head>
<body>

<div id="app" data-page='{"component":"Event","props":{"event":{"id":80,"title":"Birthda

</body>
</html>

While the initial response is HTML, Inertia does not server-side render the JavaScript
page components.

Inertia responses

Once the Inertia app has been booted, all subsequent requests to the site are
made via XHR with a X-Inertia header set to true . This header indicates that the
request is being made by Inertia and isn't a standard full-page visit.

When the server detects the X-Inertia header, instead of responding with a full
HTML document, it returns a JSON response with an encoded page object.

REQUEST

GET: http://example.com/events/80
Accept: text/html, application/xhtml+xml
X-Requested-With: XMLHttpRequest
X-Inertia: true
X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5

https://inertiajs.com/the-protocol 2/6
3/25/24, 10:19 AM The protocol - Inertia.js
RESPONSE

HTTP/1.1 200 OK
Content-Type: application/json
Vary: Accept
X-Inertia: true

{
"component": "Event",
"props": {
"event": {
"id": 80,
"title": "Birthday party",
"start_date": "2019-06-02",
"description": "Come out and celebrate Jonathan's 36th birthday party!"
}
},
"url": "/events/80",
"version": "c32b8e4965f418ad16eaebba1d4e960f"
}

The page object

Inertia shares data between the server and client via a page object. This object
includes the necessary information required to render the page component,
update the browser's history state, and track the site's asset version. The page
object includes the following four properties:

1. component: The name of the JavaScript page component.


2. props: The page props (data).
3. url: The page URL.
4. version: The current asset version.

On standard full page visits, the page object is JSON encoded into the data-page

attribute in the root <div> . On Inertia visits, the page object is returned as the
JSON payload.

https://inertiajs.com/the-protocol 3/6
3/25/24, 10:19 AM The protocol - Inertia.js

Asset versioning

One common challenge with single-page apps is refreshing site assets when
they've been changed. Inertia makes this easy by optionally tracking the current
version of the site's assets. In the event that an asset changes, Inertia will
automatically make a full-page visit instead of an XHR visit.

The Inertia page object includes a version identifier. This version identifier is set
server-side and can be a number, string, file hash, or any other value that
represents the current "version" of your site's assets, as long as the value changes
when the site's assets have been updated.

Whenever an Inertia request is made, Inertia will include the current asset version
in the X-Inertia-Version header. When the server receives the request, it compares
the asset version provided in the X-Inertia-Version header with the current asset
version. This is typically handled in the middleware layer of your server-side
framework.

If the asset versions are the same, the request simply continues as expected.
However, if the asset versions are different, the server immediately returns a
409 Conflict response, and includes the URL in a X-Inertia-Location header. This
header is necessary, since server-side redirects may have occurred. This tells
Inertia what the final intended destination URL is.

Note, 409 Conflict responses are only sent for GET requests, and not for
POST/PUT/PATCH/DELETE requests. That said, they will be sent in the event that a GET

redirect occurs after one of these requests.

If "flash" session data exists when a 409 Conflict response occurs, Inertia's server-
side framework adapters will automatically reflash this data.

REQUEST

GET: http://example.com/events/80

https://inertiajs.com/the-protocol 4/6
3/25/24, 10:19 AM The protocol - Inertia.js

Accept: text/html, application/xhtml+xml


X-Requested-With: XMLHttpRequest
X-Inertia: true
X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5

RESPONSE

409: Conflict
X-Inertia-Location: http://example.com/events/80

Partial reloads

When making Inertia requests, the partial reload option allows you to request a
subset of the props (data) from the server on subsequent visits to the same page
component. This can be a helpful performance optimization if it's acceptable that
some page data becomes stale.

When a partial reload request is made, Inertia includes two additional headers
with the request: X-Inertia-Partial-Data and X-Inertia-Partial-Component .

The X-Inertia-Partial-Data header is a comma separated list of the desired props


(data) keys that should be returned.

The X-Inertia-Partial-Component header includes the name of the component that


is being partially reloaded. This is necessary, since partial reloads only work for
requests made to the same page component. If the final destination is different
for some reason (eg. the user was logged out and is now on the login page), then
no partial reloading will occur.

REQUEST

GET: http://example.com/events
Accept: text/html, application/xhtml+xml
X-Requested-With: XMLHttpRequest
X-Inertia: true

https://inertiajs.com/the-protocol 5/6
3/25/24, 10:19 AM The protocol - Inertia.js

X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5
X-Inertia-Partial-Data: events
X-Inertia-Partial-Component: Events

RESPONSE

HTTP/1.1 200 OK
Content-Type: application/json

{
"component": "Events",
"props": {
"auth": {...}, // NOT included
"categories": [...], // NOT included
"events": [...] // included
},
"url": "/events/80",
"version": "c32b8e4965f418ad16eaebba1d4e960f"
}

https://inertiajs.com/the-protocol 6/6
3/25/24, 10:19 AM Pages - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Pages

When building applications using Inertia, each page in your application typically
has its own controller / route and a corresponding JavaScript component. This
allows you to retrieve just the data necessary for that page - no API required.

In addition, all of the data needed for the page can be retrieved before the page
is ever rendered by the browser, eliminating the need for displaying "loading"
states when users visit your application.

Creating pages

Inertia pages are simply JavaScript components. If you have ever written a Vue,
React, or Svelte component, you will feel right at home. As you can see in the
example below, pages receive data from your application's controllers as props.

Vue 2 Vue 3 React Svelte

<script setup>
import Layout from './Layout'
import { Head } from '@inertiajs/vue3'

defineProps({ user: Object })

https://inertiajs.com/pages 1/6
3/25/24, 10:19 AM Pages - Inertia.js

</script>

<template>
<Layout>
<Head title="Welcome" />
<h1>Welcome</h1>
<p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
</Layout>
</template>

Given the page above, you can render the page by returning an Inertia response
from a controller or route. In this example, let's assume this page is stored at
resources/js/Pages/User/Show.vue within a Laravel application.

use Inertia\Inertia;

class UserController extends Controller


{
public function show(User $user)
{
return Inertia::render('User/Show', [
'user' => $user
]);
}
}

Creating layouts

While not required, for most projects it makes sense to create a site layout that all
of your pages can extend. You may have noticed in our page example above that
we're wrapping the page content within a <Layout> component. Here's an example
of such a component:

Vue 2 Vue 3 React Svelte

https://inertiajs.com/pages 2/6
3/25/24, 10:19 AM Pages - Inertia.js

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

<template>
<main>
<header>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
</header>
<article>
<slot />
</article>
</main>
</template>

As you can see, there is nothing Inertia specific within this template. This is just a
typical Vue component.

Persistent layouts

While it's simple to implement layouts as children of page components, it forces


the layout instance to be destroyed and recreated between visits. This means you
cannot have persistent layout state when navigating between pages.

For example, maybe you have an audio player on a podcast website that you
want to continue playing as users navigate the site. Or, maybe you simply want to
maintain the scroll position in your sidebar navigation between page visits. In
these situations, the solution is to leverage Inertia's persistent layouts.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/pages 3/6
3/25/24, 10:19 AM Pages - Inertia.js

<script>
import Layout from './Layout'

export default {
// Using a render function...
layout: (h, page) => h(Layout, [page]),

// Using shorthand syntax...


layout: Layout,
}
</script>

<script setup>
defineProps({ user: Object })
</script>

<template>
<H1>Welcome</H1>
<p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
</template>

You can also create more complex layout arrangements using nested layouts.

Vue 2 Vue 3 React Svelte

<script>
import SiteLayout from './SiteLayout'
import NestedLayout from './NestedLayout'

export default {
// Using a render function...
layout: (h, page) => {
return h(SiteLayout, () => h(NestedLayout, () => page))
},

// Using the shorthand...


layout: [SiteLayout, NestedLayout],
}
</script>

<script setup>

https://inertiajs.com/pages 4/6
3/25/24, 10:19 AM Pages - Inertia.js

defineProps({ user: Object })


</script>

<template>
<H1>Welcome</H1>
<p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
</template>

If you're using Vue 2.7 or Vue 3, you can alternatively use the defineOptions plugin
to define a layout within <script setup> :

<script setup>
import Layout from './Layout'

defineOptions({ layout: Layout })


</script>

Default layouts

If you're using persistent layouts, you may find it convenient to define the default
page layout in the resolve() callback of your application's main JavaScript file.

Vue 2 Vue 3 React Svelte

import Layout from './Layout'

createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
let page = pages[`./Pages/${name}.vue`]
page.default.layout = page.default.layout || Layout
return page
},

https://inertiajs.com/pages 5/6
3/25/24, 10:19 AM Pages - Inertia.js

// ...
})

This will automatically set the page layout to Layout if a layout has not already
been set for that page.

You can even go a step further and conditionally set the default page layout
based on the page name , which is available to the resolve() callback. For
example, maybe you don't want the default layout to be applied to your public
pages.

Vue 2 Vue 3 React Svelte

import Layout from './Layout'

createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
let page = pages[`./Pages/${name}.vue`]
page.default.layout = name.startsWith('Public/') ? undefined : Layout
return page
},
// ...
})

https://inertiajs.com/pages 6/6
3/25/24, 10:21 AM Responses - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Responses

Creating responses

Creating an Inertia response is simple. To get started, invoke the Inertia::render()

method within your controller or route, providing both the name of the JavaScript
page component that you wish to render, as well as any props (data) for the page.

In the example below, we will pass a single prop ( event ) which contains four
attributes ( id , title , start_date and description ) to the Event/Show page
component.

use Inertia\Inertia;

class EventsController extends Controller


{
public function show(Event $event)
{
return Inertia::render('Event/Show', [
'event' => $event->only(
'id',
'title',
'start_date',
'description'
),
]);

https://inertiajs.com/responses 1/3
3/25/24, 10:21 AM Responses - Inertia.js

// Alternatively, you can use the inertia() helper...


return inertia('Event/Show', [
'event' => $event->only(
'id',
'title',
'start_date',
'description'
),
]);
}
}

Within Laravel applications, the Event/Show page would typically correspond to the file located
at resources/js/Pages/Event/Show.(js|vue|svelte).

To ensure that pages load quickly, only return the minimum data required for the
page. Also, be aware that all data returned from the controllers will be visible client-
side, so be sure to omit sensitive information.

Root template data

There are situations where you may want to access your prop data in your
application's root Blade template. For example, you may want to add a meta
description tag, Twitter card meta tags, or Facebook Open Graph meta tags. You
can access this data via the $page variable.

<meta name="twitter:title" content="{{ $page['props']['event']->title }}">

Sometimes you may even want to provide data to the root template that will not
be sent to your JavaScript page / component. This can be accomplished by
invoking the withViewData method.

https://inertiajs.com/responses 2/3
3/25/24, 10:21 AM Responses - Inertia.js

return Inertia::render('Event', ['event' => $event])


->withViewData(['meta' => $event->meta]);

After invoking the withViewData method, you can access the defined data as you
would typically access a Blade template variable.

<meta name="description" content="{{ $meta }}">

Maximum response size

To enable client-side history navigation, all Inertia server responses are stored in
the browser's history state. However, keep in mind that some browsers impose a
size limit on how much data can be saved within the history state.

For example, Firefox has a size limit of 640k characters and throws a
NS_ERROR_ILLEGAL_VALUE error if you exceed this limit. Typically, this is much more data
than you'll ever practically need when building applications.

https://inertiajs.com/responses 3/3
3/25/24, 10:21 AM Redirects - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Redirects

When making a non-GET Inertia request manually or via a <Link> element, you
should ensure that you always respond with a proper Inertia redirect response.

For example, if your controller is creating a new user, your "store" endpoint should
return a redirect back to a standard GET endpoint, such as your user "index" page.
Inertia will automatically follow this redirect and update the page accordingly.

class UsersController extends Controller


{
public function index()
{
return Inertia::render('Users/Index', [
'users' => User::all(),
]);
}

public function store(Request $request)


{
User::create(
$request->validate([
'name' => ['required', 'max:50'],
'email' => ['required', 'max:50', 'email'],
])
);

return to_route('users.index');

https://inertiajs.com/redirects 1/2
3/25/24, 10:21 AM Redirects - Inertia.js

}
}

303 response code

When redirecting after a PUT , PATCH , or DELETE request, you must use a 303

response code, otherwise the subsequent request will not be treated as a GET

request. A 303 redirect is very similar to a 302 redirect; however, the follow-up
request is explicitly changed to a GET request.

If you're using one of our official server-side adapters, all redirects will
automatically be converted to 303 redirects.

External redirects

Sometimes it's necessary to redirect to an external website, or even another non-


Inertia endpoint in your app while handling an Inertia request. This can be
accomplished using a server-side initiated window.location visit via the
Inertia::location() method.

return Inertia::location($url);

The Inertia::location() method will generate a 409 Conflict response and include
the destination URL in the X-Inertia-Location header. When this response is
received client-side, Inertia will automatically perform a window.location = url visit.

https://inertiajs.com/redirects 2/2
3/25/24, 10:21 AM Routing - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Routing

Defining routes

When using Inertia, all of your application's routes are defined server-side. This
means that you don't need Vue Router or React Router. Instead, you can simply
define Laravel routes and return Inertia responses from those routes.

Shorthand routes

If you have a page that doesn't need a corresponding controller method, like an
"FAQ" or "about" page, you can route directly to a component via the
Route::inertia() method.

Route::inertia('/about', 'About');

Generating URLs

https://inertiajs.com/routing 1/3
3/25/24, 10:21 AM Routing - Inertia.js

Some server-side frameworks allow you to generate URLs from named routes.
However, you will not have access to those helpers client-side. Here are a couple
ways to still use named routes with Inertia.

The first option is to generate URLs server-side and include them as props. Notice
in this example how we're passing the edit_url and create_url to the Users/Index

component.

class UsersController extends Controller


{
public function index()
{
return Inertia::render('Users/Index', [
'users' => User::all()->map(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'edit_url' => route('users.edit', $user),
];
}),
'create_url' => route('users.create'),
]);
}
}

However, when using Laravel, the Ziggy library can make your named, server-side
routes available to you via a global route() function. In fact, if you are developing
an application using one of Laravel's starter kits, Ziggy is already configured for
you.

If you're using Ziggy with Vue, it's helpful to make this function available as a
custom $route property so you can use it directly in your templates.

Vue 2 Vue 3

https://inertiajs.com/routing 2/3
3/25/24, 10:21 AM Routing - Inertia.js

app.config.globalProperties.$route = route

<Link :href="$route('users.create')">Create User</Link>

https://inertiajs.com/routing 3/3
3/25/24, 10:21 AM Title & meta - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Title & meta

Since Inertia powered JavaScript apps are rendered within the document <body> ,

they are unable to render markup to the document <head> , as it's outside of their
scope. To help with this, Inertia ships with a <Head> component which can be used
to set the page <title> , <meta> tags, and other <head> elements.

The <Head> component will only replace <head> elements that are not in your server-
side root template.

The <Head> component is not available in the Svelte adapter, as Svelte already ships
with its own <svelte:head> component.

Head component

To add <head> elements to your page, use the <Head> component. Within this
component, you can include the elements that you wish to add to the document
<head> .

Vue 2 Vue 3 React Svelte

https://inertiajs.com/title-and-meta 1/5
3/25/24, 10:21 AM Title & meta - Inertia.js

import { Head } from '@inertiajs/vue3'

<Head>
<title>Your page title</title>
<meta name="description" content="Your page description">
</Head>

Title shorthand

If you only need to add a <title> to the document <head> , you may simply pass
the title as a prop to the <Head> component.

Vue 2 Vue 3 React Svelte

import { Head } from '@inertiajs/vue3'

<Head title="Your page title" />

Title callback

You can globally modify the page <title> using the title callback in the
createInertiaApp setup method. Typically, this method is invoked in your
application's main JavaScript file. A common use case for the title callback is
automatically adding an app name before or after each page title.

createInertiaApp({
title: title => `${title} - My App`,
// ...
})

https://inertiajs.com/title-and-meta 2/5
3/25/24, 10:21 AM Title & meta - Inertia.js

After defining the title callback, the callback will automatically be invoked when
you set a title using the <Head> component.

Vue 2 Vue 3 React Svelte

import { Head } from '@inertiajs/vue3'

<Head title="Home">

Which, in this example, will result in the following <title> tag.

<title>Home - My App</title>

The title callback will also be invoked when you set the title using a <title> tag
within your <Head> component.

Vue 2 Vue 3 React Svelte

import { Head } from '@inertiajs/vue3'

<Head>
<title>Home</title>
</Head>

Multiple Head instances

It's possible to have multiple instances of the <Head> component throughout your
application. For example, your layout can set some default <Head> elements, and
then your individual pages can override those defaults.

https://inertiajs.com/title-and-meta 3/5
3/25/24, 10:21 AM Title & meta - Inertia.js

Vue 2 Vue 3 React Svelte

// Layout.vue

import { Head } from '@inertiajs/vue3'

<Head>
<title>My app</title>
<meta head-key="description" name="description" content="This is the default descripti
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</Head>

// About.vue

import { Head } from '@inertiajs/vue3'

<Head>
<title>About - My app</title>
<meta head-key="description" name="description" content="This is a page specific descr
</Head>

Inertia will only ever render one <title> tag; however, all other tags will be stacked
since it's valid to have multiple instances of them. To avoid duplicate tags in your
<head> , you can use the head-key property, which will make sure the tag is only
rendered once. This is illustrated in the example above for the
<meta name="description"> tag.

The code example above will render the following HTML.

<head>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>About - My app</title>
<meta name="description" content="This is a page specific description" />
</head>

https://inertiajs.com/title-and-meta 4/5
3/25/24, 10:21 AM Title & meta - Inertia.js

Head extension

When building a real application, it can sometimes be helpful to create a custom


head component that extends Inertia's <Head> component. This gives you a place
to set app-wide defaults, such as appending the app name to the page title.

Vue 2 Vue 3 React Svelte

<!-- AppHead.vue -->

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

defineProps({ title: String })


</script>

<template>
<Head :title="title ? `${title} - My App` : 'My App'">
<slot />
</Head>
</template>

Once you have created the custom component, you may simply start using the
custom component in your pages.

Vue 2 Vue 3 React Svelte

import AppHead from './AppHead'

<AppHead title="About" />

https://inertiajs.com/title-and-meta 5/5
3/25/24, 10:21 AM Links - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Links

To create links to other pages within an Inertia app, you will typically use the
Inertia <Link> component. This component is a light wrapper around a standard
anchor <a> link that intercepts click events and prevents full page reloads. This is
how Inertia provides a single-page app experience once your application has
been loaded.

Creating links

To create an Inertia link, use the Inertia <Link> component. Any attributes you
provide to this component will be proxied to the underlying HTML tag.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/">Home</Link>

By default, Inertia renders links as anchor <a> elements. However, you can change
the tag using the as attribute.

https://inertiajs.com/links 1/6
3/25/24, 10:21 AM Links - Inertia.js

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/logout" method="post" as="button" type="button">Logout</Link>

// Renders as...
<button type="button">Logout</button>

Creating POST / PUT / PATCH / DELETE anchor <a> links is discouraged as it causes
"Open Link in New Tab / Window" accessibility issues. Instead, consider using a more
appropriate element, such as a <button> .

Method

You can specify the HTTP request method for an Inertia link request using the
method attribute. The default method used by links is GET , but you can use the
method attribute to make POST , PUT , PATCH , and DELETE requests via links.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/logout" method="post" as="button">Logout</Link>

Data

When making POST or PUT requests, you may wish to add additional data to the
request. You can accomplish this using the data attribute. The provided data can

https://inertiajs.com/links 2/6
3/25/24, 10:21 AM Links - Inertia.js

be an object or FormData instance.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/endpoint" method="post" :data="{ foo: bar }">Save</Link>

Custom headers

The headers attribute allows you to add custom headers to an Inertia link.
However, the headers Inertia uses internally to communicate its state to the server
take priority and therefore cannot be overwritten.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/endpoint" :headers="{ foo: bar }">Save</Link>

Browser history

The replace attribute allows you to specify the browser's history behaviour. By
default, page visits push (new) state ( window.history.pushState ) into the history;
however, it's also possible to replace state ( window.history.replaceState ) by setting
the replace attribute to true. This will cause the visit to replace the current history
state instead of adding a new history state to the stack.

https://inertiajs.com/links 3/6
3/25/24, 10:21 AM Links - Inertia.js

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/" replace>Home</Link>

State preservation

You can preserve a page component's local state using the preserve-state

attribute. This will prevent a page component from fully re-rendering. The
preserve-state attribute is especially helpful on pages that contain forms, since you
can avoid manually repopulating input fields and can also maintain a focused
input.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<input v-model="query" type="text" />

<Link href="/search" :data="{ query }" preserve-state>Search</Link>

Scroll preservation

You can use the preserve-scroll attribute to prevent Inertia from automatically
resetting the scroll position when making a page visit.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/links 4/6
3/25/24, 10:21 AM Links - Inertia.js

import { Link } from '@inertiajs/vue3'

<Link href="/" preserve-scroll>Home</Link>

For more information on managing scroll position, please consult the


documentation on scroll management.

Partial reloads

The only attribute allows you to specify that only a subset of a page's props
(data) should be retrieved from the server on subsequent visits to that page.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/users?active=true" :only="['users']">Show active</Link>

For more information on this topic, please consult the complete documentation on
partial reloads.

Active states

It's often desirable to set an active state for navigation links based on the current
page. This can be accomplished when using Inertia by inspecting the page object
and doing string comparisons against the page.url and page.component properties.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/links 5/6
3/25/24, 10:21 AM Links - Inertia.js

import { Link } from '@inertiajs/vue3'

// URL exact match...


<Link href="/users" :class="{ 'active': $page.url === '/users' }">Users</Link>

// Component exact match...


<Link href="/users" :class="{ 'active': $page.component === 'Users/Index' }">Users</Link

// URL starts with (/users, /users/create, /users/1, etc.)...


<Link href="/users" :class="{ 'active': $page.url.startsWith('/users') }">Users</Link>

// Component starts with (Users/Index, Users/Create, Users/Show, etc.)...


<Link href="/users" :class="{ 'active': $page.component.startsWith('Users') }">Users</Li

You can perform exact match comparisons ( === ), startsWith() comparisons (useful
for matching a subset of pages), or even more complex comparisons using regular
expressions.

Using this approach, you're not limited to just setting class names. You can use this
technique to conditionally render any markup on active state, such as different link
text or even an SVG icon that represents the link is active.

https://inertiajs.com/links 6/6
3/25/24, 10:21 AM Manual visits - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Manual visits

In addition to creating links, it's also possible to manually make Inertia visits /
requests programatically via JavaScript. This is accomplished via the
router.visit() method.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.visit(url, {
method: 'get',
data: {},
replace: false,
preserveState: false,
preserveScroll: false,
only: [],
headers: {},
errorBag: null,
forceFormData: false,
onCancelToken: cancelToken => {},
onCancel: () => {},
onBefore: visit => {},
onStart: visit => {},
onProgress: progress => {},
onSuccess: page => {},
onError: errors => {},

https://inertiajs.com/manual-visits 1/10
3/25/24, 10:21 AM Manual visits - Inertia.js

onFinish: visit => {},


})

However, it's generally more convenient to use one of Inertia's shortcut request
methods. These methods share all the same options as router.visit() .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.get(url, data, options)


router.post(url, data, options)
router.put(url, data, options)
router.patch(url, data, options)
router.delete(url, options)
router.reload(options) // Uses the current URL

The reload() method is a convenient, shorthand method that automatically visits


the current page with preserveState and preserveScroll both set to true , making it
the perfect method to invoke when you just want to reload the current page's
data.

Method

When making manual visits, you may use the method option to set the request's
HTTP method to get , post , put , patch or delete . The default method is get .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

https://inertiajs.com/manual-visits 2/10
3/25/24, 10:21 AM Manual visits - Inertia.js

router.visit(url, { method: 'post' })

Uploading files via put or patch is not supported in Laravel. Instead, make the
request via post , including a _method field set to put or patch . This is called form
method spoofing.

Data

You may use the data option to add data to the request.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.visit('/users', {
method: 'post',
data: {
name: 'John Doe',
email: 'john.doe@example.com',
},
})

For convenience, the get() , post() , put() , and patch() methods all accept data

as their second argument.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', {
name: 'John Doe',

https://inertiajs.com/manual-visits 3/10
3/25/24, 10:21 AM Manual visits - Inertia.js

email: 'john.doe@example.com',
})

Custom headers

The headers option allows you to add custom headers to a request.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
headers: {
'Custom-Header': 'value',
},
})

The headers Inertia uses internally to communicate its state to the server take priority
and therefore cannot be overwritten.

File uploads

When making visits / requests that include files, Inertia will automatically convert
the request data into a FormData object. If you would like the request to always use
a FormData object, you may use the forceFormData option.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

https://inertiajs.com/manual-visits 4/10
3/25/24, 10:21 AM Manual visits - Inertia.js

router.post('/companies', data, {
forceFormData: true,
})

For more information on uploading files, please consult the dedicated file uploads
documentation.

Browser history

When making visits, Inertia automatically adds a new entry into the browser
history. However, it's also possible to replace the current history entry by setting the
replace option to true .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.get('/users', { search: 'John' }, { replace: true })

Visits made to the same URL automatically set replace to true .

State preservation

By default, page visits to the same page create a fresh page component instance.
This causes any local state, such as form inputs, scroll positions, and focus states
to be lost.

However, in some situations, it's necessary to preserve the page component state.
For example, when submitting a form, you need to preserve your form data in the
https://inertiajs.com/manual-visits 5/10
3/25/24, 10:21 AM Manual visits - Inertia.js

event that form validation fails on the server.

You can instruct Inertia to preserve the component's state by setting the
preserveState option to true .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.get('/users', { search: 'John' }, { preserveState: true })

You can also lazily evaluate the preserveState option based on the response by
providing a callback to the preserveState option.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
preserveState: (page) => Object.keys(page.props.errors).length,
})

For convenience, the post , put , patch , delete , and reload methods all set the
preserveState option to true by default.

Scroll preservation

When navigating between pages, Inertia mimics default browser behaviour by


automatically resetting the scroll position of the document body (as well as any
scroll regions you've defined) back to the top of the page. However, you may use
the preserveScroll option to disable this behaviour.
https://inertiajs.com/manual-visits 6/10
3/25/24, 10:21 AM Manual visits - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.visit(url, { preserveScroll: true })

You can also lazily evaluate the preserveScroll option based on the response by
providing a callback.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
preserveScroll: (page) => Object.keys(page.props.errors).length,
})

For more information regarding this feature, please consult the scroll management
documentation.

Partial reloads

The only option allows you to request a subset of the props (data) from the server
on subsequent visits to the same page, thus making your application more
efficient since it does not need to retrieve data that the page is not interested in
refreshing.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/manual-visits 7/10
3/25/24, 10:21 AM Manual visits - Inertia.js

import { router } from '@inertiajs/vue3'

router.visit('/users', { search: 'John' }, { only: ['users'] })

For more information on this feature, please consult the partial reloads
documentation.

Visit cancellation

You can cancel a visit using a cancel token, which Inertia automatically generates
and provides via the onCancelToken() callback prior to making the visit.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
onCancelToken: (cancelToken) => (this.cancelToken = cancelToken),
})

// Cancel the visit...


this.cancelToken.cancel()

The onCancel() and onFinish() event callbacks will be executed when a visit is
cancelled.

Event callbacks

In addition to Inertia's global events, Inertia also provides a number of per-visit


event callbacks.

https://inertiajs.com/manual-visits 8/10
3/25/24, 10:21 AM Manual visits - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
onBefore: (visit) => {},
onStart: (visit) => {},
onProgress: (progress) => {},
onSuccess: (page) => {},
onError: (errors) => {},
onCancel: () => {},
onFinish: visit => {},
})

Returning false from the onBefore() callback will cause the visit to be cancelled.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.delete(`/users/${user.id}`, {
onBefore: () => confirm('Are you sure you want to delete this user?'),
})

It's also possible to return a promise from the onSuccess() and onError() callbacks.
When doing so, the "finish" event will be delayed until the promise has resolved.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post(url, {
onSuccess: () => {
return Promise.all([
this.doThing(),

https://inertiajs.com/manual-visits 9/10
3/25/24, 10:21 AM Manual visits - Inertia.js

this.doAnotherThing()
])
}
onFinish: visit => {
// This won't be called until doThing()
// and doAnotherThing() have finished.
},
})

https://inertiajs.com/manual-visits 10/10
3/25/24, 10:21 AM Forms - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Forms

Submitting forms

While it's possible to make classic HTML form submissions with Inertia, it's not
recommended since they cause full-page reloads. Instead, it's better to intercept
form submissions and then make the request using Inertia.

Vue 2 Vue 3 React Svelte

<script setup>
import { reactive } from 'vue'
import { router } from '@inertiajs/vue3'

const form = reactive({


first_name: null,
last_name: null,
email: null,
})

function submit() {
router.post('/users', form)
}
</script>

<template>
<form @submit.prevent="submit">
<label for="first_name">First name:</label>
https://inertiajs.com/forms 1/9
3/25/24, 10:21 AM Forms - Inertia.js

<input id="first_name" v-model="form.first_name" />


<label for="last_name">Last name:</label>
<input id="last_name" v-model="form.last_name" />
<label for="email">Email:</label>
<input id="email" v-model="form.email" />
<button type="submit">Submit</button>
</form>
</template>

As you may have noticed in the example above, when using Inertia, you don't
typically need to inspect form responses client-side like you would when making
XHR / fetch requests manually.

Instead, your server-side route / controller typically issues a redirect response.


And, Of course, there is nothing stopping you from redirecting the user right back
to the page they were previously on. Using this approach, handling Inertia form
submissions feels very similar to handling classic HTML form submissions.

class UsersController extends Controller


{
public function index()
{
return Inertia::render('Users/Index', [
'users' => User::all(),
]);
}

public function store(Request $request)


{
User::create($request->validate([
'first_name' => ['required', 'max:50'],
'last_name' => ['required', 'max:50'],
'email' => ['required', 'max:50', 'email'],
]));

return to_route('users.index');
}
}

https://inertiajs.com/forms 2/9
3/25/24, 10:21 AM Forms - Inertia.js

Server-side validation

Handling server-side validation errors in Inertia works a little different than


handling errors from manual XHR / fetch requests. When making XHR / fetch
requests, you typically inspect the response for a 422 status code and manually
update the form's error state.

However, when using Inertia, a 422 response is never returned by your server.
Instead, as we saw in the example above, your routes / controllers will typically
return a redirect response - much like a classic, full-page form submission.

For a full discussion on handling and displaying validation errors with Inertia,
please consult the validation documentation.

Form helper

Since working with forms is so common, Inertia includes a form helper designed to
help reduce the amount of boilerplate code needed for handling typical form
submissions.

Vue 2 Vue 3 React Svelte

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

const form = useForm({


email: null,
password: null,
remember: false,
})
</script>

<template>
<form @submit.prevent="form.post('/login')">
<!-- email -->

https://inertiajs.com/forms 3/9
3/25/24, 10:21 AM Forms - Inertia.js

<input type="text" v-model="form.email">


<div v-if="form.errors.email">{{ form.errors.email }}</div>
<!-- password -->
<input type="password" v-model="form.password">
<div v-if="form.errors.password">{{ form.errors.password }}</div>
<!-- remember me -->
<input type="checkbox" v-model="form.remember"> Remember Me
<!-- submit -->
<button type="submit" :disabled="form.processing">Login</button>
</form>
</template>

To submit the form, you may use the get , post , put , patch and delete methods.

Vue 2 Vue 3 React Svelte

form.submit(method, url, options)


form.get(url, options)
form.post(url, options)
form.put(url, options)
form.patch(url, options)
form.delete(url, options)

The submit methods support all of the typical visit options, such as preserveState ,

preserveScroll , and event callbacks, which can be helpful for performing tasks on
successful form submissions. For example, you might use the onSuccess callback to
reset inputs to their original state.

Vue 2 Vue 3 React Svelte

form.post('/profile', {
preserveScroll: true,
onSuccess: () => form.reset('password'),
})

https://inertiajs.com/forms 4/9
3/25/24, 10:21 AM Forms - Inertia.js

If you need to modify the form data before it's sent to the server, you can do so via
the transform() method.

Vue 2 Vue 3 React Svelte

form
.transform((data) => ({
...data,
remember: data.remember ? 'on' : '',
}))
.post('/login')

You can use the processing property to track if a form is currently being submitted.
This can be helpful for preventing double form submissions by disabling the submit
button.

Vue 2 Vue 3 React Svelte

<button type="submit" :disabled="form.processing">Submit</button>

If your form is uploading files, the current progress event is available via the
progress property, allowing you to easily display the upload progress.

Vue 2 Vue 3 React Svelte

<progress v-if="form.progress" :value="form.progress.percentage" max="100">


{{ form.progress.percentage }}%
</progress>

https://inertiajs.com/forms 5/9
3/25/24, 10:21 AM Forms - Inertia.js

If there are form validation errors, they are available via the errors property. When
building Laravel powered Inertia applications, form errors will automatically be
populated when your application throws instances of ValidationException , such as
when using $request->validate() .

Vue 2 Vue 3 React Svelte

<div v-if="form.errors.email">{{ form.errors.email }}</div>

For a more thorough discussion of form validation and errors, please consult the
validation documentation.

To determine if a form has any errors, you may use the hasErrors property. To clear
form errors, use the clearErrors() method.

Vue 2 Vue 3 React Svelte

// Clear all errors...


form.clearErrors()

// Clear errors for specific fields...


form.clearErrors('field', 'anotherfield')

If you're using a client-side input validation libraries or do client-side validation


manually, you can set your own errors on the form using the setErrors() method.

Vue 2 Vue 3 React Svelte

// Set a single error...


form.setError('field', 'Your error message.');

https://inertiajs.com/forms 6/9
3/25/24, 10:21 AM Forms - Inertia.js

// Set multiple errors at once...


form.setError({
foo: 'Your error message for the foo field.',
bar: 'Some other error for the bar field.'
});

Unlike an actual form submission, the page's props remain unchanged when manually
setting errors on a form instance.

When a form has been successfully submitted, the wasSuccessful property will be
true . In addition to this, forms have a recentlySuccessful property, which will be set
to true for two seconds after a successful form submission. This property can be
utilized to show temporary success messages.

To reset the form's values back to their default values, you can use the reset()

method.

Vue 2 Vue 3 React Svelte

// Reset the form...


form.reset()

// Reset specific fields...


form.reset('field', 'anotherfield')

If your form's default values become outdated, you can use the defaults() method
to update them. Then, the form will be reset to the correct values the next time the
reset() method is invoked.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/forms 7/9
3/25/24, 10:21 AM Forms - Inertia.js

// Set the form's current values as the new defaults...


form.defaults()

// Update the default value of a single field...


form.defaults('email', 'updated-default@example.com')

// Update the default value of multiple fields...


form.defaults({
name: 'Updated Example',
email: 'updated-default@example.com',
})

To determine if a form has any changes, you may use the isDirty property.

Vue 2 Vue 3 React Svelte

<div v-if="form.isDirty">There are unsaved form changes.</div>

To cancel a form submission, use the cancel() method.

Vue 2 Vue 3 React Svelte

form.cancel()

To instruct Inertia to store a form's data and errors in history state, you can provide
a unique form key as the first argument when instantiating your form.

Vue 2 Vue 3 React Svelte

import { useForm } from '@inertiajs/vue3'

https://inertiajs.com/forms 8/9
3/25/24, 10:21 AM Forms - Inertia.js

const form = useForm('CreateUser', data)


const form = useForm(`EditUser:${user.id}`, data)

File uploads

When making requests or form submissions that include files, Inertia will
automatically convert the request data into a FormData object.

For a more thorough discussion of file uploads, please consult the file uploads
documentation.

XHR / fetch submissions

Using Inertia to submit forms works great for the vast majority of situations;
however, in the event that you need more control over the form submission, you're
free to make plain XHR or fetch requests instead using the library of your choice.

https://inertiajs.com/forms 9/9
3/25/24, 10:21 AM File uploads - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

File uploads

FormData conversion

When making Inertia requests that include files (even nested files), Inertia will
automatically convert the request data into a FormData object. This conversion is
necessary in order to submit a multipart/form-data request via XHR.

If you would like the request to always use a FormData object regardless of whether
a file is present in the data, you may provide the forceFormData option when
making the request.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', data, {
forceFormData: true,
})

You can learn more about the FormData interface via its MDN documentation.

https://inertiajs.com/file-uploads 1/3
3/25/24, 10:21 AM File uploads - Inertia.js

Prior to version 0.8.0, Inertia did not automatically convert requests to FormData . If
you're using an Inertia release prior to this version, you will need to manually perform
this conversion.

File upload example

Let's examine a complete file upload example using Inertia. This example includes
both a name text input and an avatar file input.

Vue 2 Vue 3 React Svelte

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

const form = useForm({


name: null,
avatar: null,
})

function submit() {
form.post('/users')
}
</script>

<template>
<form @submit.prevent="submit">
<input type="text" v-model="form.name" />
<input type="file" @input="form.avatar = $event.target.files[0]" />
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
{{ form.progress.percentage }}%
</progress>
<button type="submit">Submit</button>
</form>
</template>

https://inertiajs.com/file-uploads 2/3
3/25/24, 10:21 AM File uploads - Inertia.js

This example uses the Inertia form helper for convenience, since the form helper
provides easy access to the current upload progress. However, you are free to
submit your forms using manual Inertia visits as well.

Multipart limitations

Uploading files using a multipart/form-data request is not natively supported in


some server-side frameworks when using the PUT , PATCH , or DELETE HTTP methods.
The simplest workaround for this limitation is to simply upload files using a POST

request instead.

However, some frameworks, such as Laravel and Rails, support form method
spoofing, which allows you to upload the files using POST , but have the framework
handle the request as a PUT or PATCH request. This is done by including a _method

attribute in the data of your request.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post(`/users/${user.id}`, {
_method: 'put',
avatar: form.avatar,
})

https://inertiajs.com/file-uploads 3/3
3/25/24, 10:21 AM Validation - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Validation

How it works

Handling server-side validation errors in Inertia works differently than a classic


XHR-driven form that requires you to catch the validation errors from 422

responses and manually update the form's error state - because Inertia never
receives 422 responses. Instead, Inertia operates much more like a standard full
page form submission. Here's how:

First, you submit your form using Inertia. If there are server-side validation errors,
you don't return those errors as a 422 JSON response. Instead, you redirect (server-
side) the user back to the form page they were previously on, flashing the
validation errors in the session. Some frameworks, such as Laravel, do this
automatically.

Next, any time these validation errors are present in the session, they
automatically get shared with Inertia, making them available client-side as page
props which you can display in your form. Since props are reactive, they are
automatically shown when the form submission completes.

Finally, since Inertia apps never generate 422 responses, Inertia needs another
way to determine if a response includes validation errors. To do this, Inertia checks

https://inertiajs.com/validation 1/5
3/25/24, 10:21 AM Validation - Inertia.js

the page.props.errors object for the existence of any errors. In the event that errors
are present, the request's onError() callback will be called instead of the
onSuccess() callback.

Sharing errors

In order for your server-side validation errors to be available client-side, your


server-side framework must share them via the errors prop. Inertia's first-party
adapters, such as the Laravel adapter, do this automatically. For other
frameworks, you may need to do this manually. Please refer to your specific server-
side adapter documentation for more information.

Displaying errors

Since validation errors are made available client-side as page component props,
you can conditionally display them based on their existence. Remember, when
using our first-party server adapters (such as the Laravel adapter), the errors

prop will automatically be available to your page.

Vue 2 Vue 3 React Svelte

<script setup>
import { reactive } from 'vue'
import { router } from '@inertiajs/vue3'

defineProps({ errors: Object })

const form = reactive({


first_name: null,
last_name: null,
email: null,
})

https://inertiajs.com/validation 2/5
3/25/24, 10:21 AM Validation - Inertia.js

function submit() {
router.post('/users', form)
}
</script>

<template>
<form @submit.prevent="submit">
<label for="first_name">First name:</label>
<input id="first_name" v-model="form.first_name" />
<div v-if="errors.first_name">{{ errors.first_name }}</div>
<label for="last_name">Last name:</label>
<input id="last_name" v-model="form.last_name" />
<div v-if="errors.last_name">{{ errors.last_name }}</div>
<label for="email">Email:</label>
<input id="email" v-model="form.email" />
<div v-if="errors.email">{{ errors.email }}</div>
<button type="submit">Submit</button>
</form>
</template>

When using the Vue adapters, you may also access the errors via the
$page.props.errors object.

Repopulating input

While handling errors in Inertia is similar to full page form submissions, Inertia offers
even more benefits. In fact, you don't even need to manually repopulate old form
input data.

When validation errors occur, the user is typically redirected back to the form
page they were previously on. And, by default, Inertia automatically preserves the
component state for post , put , patch , and delete requests. Therefore, all the old
form input data remains exactly as it was when the user submitted the form.

So, the only work remaining is to display any validation errors using the errors

prop.
https://inertiajs.com/validation 3/5
3/25/24, 10:21 AM Validation - Inertia.js

Error bags

If you're using the form helper, it's not necessary to use error bags since validation
errors are automatically scoped to the form object making the request.

For pages that have more than one form, it's possible to encounter conflicts when
displaying validation errors if two forms share the same field names. For example,
imagine a "create company" form and a "create user" form that both have a name

field. Since both forms will be displaying the page.props.errors.name validation error,
generating a validation error for the name field in either form will cause the error to
appear in both forms.

To solve this issue, you can use "error bags". Error bags scope the validation errors
returned from the server within a unique key specific to that form. Continuing with
our example above, you might have a createCompany error bag for the first form and
a createUser error bag for the second form.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/companies', data, {
errorBag: 'createCompany',
})

router.post('/users', data, {
errorBag: 'createUser',
})

Specifying an error bag will cause the validation errors to come back from the
server within page.props.errors.createCompany and page.props.errors.createUser .

https://inertiajs.com/validation 4/5
3/25/24, 10:21 AM Validation - Inertia.js

https://inertiajs.com/validation 5/5
3/25/24, 10:21 AM Shared data - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Shared data

Sometimes you need to access specific pieces of data on numerous pages within
your application. For example, you may need to display the current user in the site
header. Passing this data manually in each response across your entire application
is cumbersome. Thankfully, there is a better option: shared data.

Sharing data

Inertia's server-side adapters all provide a method of making shared data


available for every request. This is typically done outside of your controllers.
Shared data will be automatically merged with the page props provided in your
controller.

In Laravel applications, this is typically handled by the HandleInertiaRequests

middleware that is automatically installed when installing the server-side adapter.

class HandleInertiaRequests extends Middleware


{
public function share(Request $request)
{
return array_merge(parent::share($request), [
// Synchronously...
'appName' => config('app.name'),
https://inertiajs.com/shared-data 1/4
3/25/24, 10:21 AM Shared data - Inertia.js

// Lazily...
'auth.user' => fn () => $request->user()
? $request->user()->only('id', 'name', 'email')
: null,
]);
}
}

The HandleInertiaRequests middleware provides a "share" method where you can define the
data that is automatically shared with each Inertia response.

Alternatively, you can manually share data using the Inertia::share method.

use Inertia\Inertia;

// Synchronously...
Inertia::share('appName', config('app.name'));

// Lazily...
Inertia::share('user', fn (Request $request) => $request->user()
? $request->user()->only('id', 'name', 'email')
: null
);

Shared data should be used sparingly as all shared data is included with every
response.

Page props and shared data are merged together, so be sure to namespace your
shared data appropriately to avoid collisions.

Accessing shared data

https://inertiajs.com/shared-data 2/4
3/25/24, 10:21 AM Shared data - Inertia.js

Once you have shared the data server-side, you will be able to access it within
any of your pages or components. Here's an example of how to access shared
data in a layout component.

Vue 2 Vue 3 React Svelte

<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'

const page = usePage()

const user = computed(() => page.props.auth.user)


</script>

<template>
<main>
<header>
You are logged in as: {{ user.name }}
</header>
<content>
<slot />
</content>
</main>
</template>

Flash messages

Another great use-case for shared data is flash messages. These are messages
stored in the session only for the next request. For example, it's common to set a
flash message after completing a task and before redirecting to a different page.

Here's a simple way to implement flash messages in your Inertia applications. First,
share the flash message on each request.

https://inertiajs.com/shared-data 3/4
3/25/24, 10:21 AM Shared data - Inertia.js

class HandleInertiaRequests extends Middleware


{
public function share(Request $request)
{
return array_merge(parent::share($request), [
'flash' => [
'message' => fn () => $request->session()->get('message')
],
]);
}
}

Next, display the flash message in a frontend component, such as the site layout.

Vue 2 Vue 3 React Svelte

<template>
<main>
<header></header>
<content>
<div v-if="$page.props.flash.message" class="alert">
{{ $page.props.flash.message }}
</div>
<slot />
</content>
<footer></footer>
</main>
</template>

https://inertiajs.com/shared-data 4/4
3/25/24, 10:22 AM Events - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Events

Inertia provides an event system that allows you to "hook into" the various lifecycle
events of the library.

Registering listeners

To register an event listener, use the router.on() method.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('start', (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
})

Under the hood, Inertia uses native browser events, so you can also interact with
Inertia events using the typical event methods you may already be familiar with -
just be sure to prepend inertia: to the event name.

https://inertiajs.com/events 1/10
3/25/24, 10:22 AM Events - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

document.addEventListener('inertia:start', (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
})

Removing listeners

When you register an event listener, Inertia automatically returns a callback that
can be invoked to remove the event listener.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

let removeStartEventListener = router.on('start', (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
})

// Remove the listener...


removeStartEventListener()

Combined with hooks, you can automatically remove the event listener when
components unmount.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'


import { onUnmounted } from 'vue'

onUnmounted(
https://inertiajs.com/events 2/10
3/25/24, 10:22 AM Events - Inertia.js

router.on('start', (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
})
)

Alternatively, if you're using native browser events, you can remove the event
listener using removeEventListener() .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

let startEventListener = (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
}

document.addEventListener('inertia:start', startEventListener)

// Remove the listener...


document.removeEventListener('inertia:start', startEventListener)

Cancelling events

Some events, such as before , invalid , and error , support cancellation, allowing
you to prevent Inertia's default behaviour. Just like native events, the event will be
cancelled if only one event listener calls event.preventDefault() .

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('before', (event) => {


if (!confirm('Are you sure you want to navigate away?')) {
event.preventDefault()

https://inertiajs.com/events 3/10
3/25/24, 10:22 AM Events - Inertia.js

}
})

For convenience, if you register your event listener using router.on() , you can
cancel the event by returning false from the listener.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('before', (event) => {


return confirm('Are you sure you want to navigate away?')
})

Note, browsers do not allow cancelling the native popstate event, so preventing
forward and back history visits while using Inertia.js is not possible.

Before

The before event fires when a request is about to be made to the server. This is
useful for intercepting visits.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('before', (event) => {


console.log(`About to make a visit to ${event.detail.visit.url}`)
})

The primary purpose of this event is to allow you to prevent a visit from happening.
https://inertiajs.com/events 4/10
3/25/24, 10:22 AM Events - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('before', (event) => {


return confirm('Are you sure you want to navigate away?')
})

Start

The start event fires when a request to the server has started. This is useful for
displaying loading indicators.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('start', (event) => {


console.log(`Starting a visit to ${event.detail.visit.url}`)
})

The start event is not cancelable.

Progress

The progress event fires as progress increments during file uploads.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/events 5/10
3/25/24, 10:22 AM Events - Inertia.js

import { router } from '@inertiajs/vue3'

router.on('progress', (event) => {


this.form.progress = event.detail.progress.percentage
})

The progress event is not cancelable.

Success

The success event fires on successful page visits, unless validation errors are
present. However, this does not include history visits.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('success', (event) => {


console.log(`Successfully made a visit to ${event.detail.page.url}`)
})

The success event is not cancelable.

Error

The error event fires when validation errors are present on "successful" page visits.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/events 6/10
3/25/24, 10:22 AM Events - Inertia.js

import { router } from '@inertiajs/vue3'

router.on('error', (errors) => {


console.log(errors)
})

The error event is not cancelable.

Invalid

The invalid event fires when a non-Inertia response is received from the server,
such as an HTML or vanilla JSON response. A valid Inertia response is a response
that has the X-Inertia header set to true with a json payload containing the
page object.

This event is fired for all response types, including 200 , 400 , and 500 response
codes.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('invalid', (event) => {


console.log(`An invalid Inertia response was received.`)
console.log(event.detail.response)
})

You may cancel the invalid event to prevent Inertia from showing the non-Inertia
response modal.

https://inertiajs.com/events 7/10
3/25/24, 10:22 AM Events - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('invalid', (event) => {


event.preventDefault()

// Handle the invalid response yourself...


})

Exception

The exception event fires on unexpected XHR errors such as network interruptions.
In addition, this event fires for errors generated when resolving page components.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('exception', (event) => {


console.log(`An unexpected error occurred during an Inertia visit.`)
console.log(event.detail.error)
})

You may cancel the exception event to prevent the error from being thrown.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('exception', (event) => {


event.preventDefault()

https://inertiajs.com/events 8/10
3/25/24, 10:22 AM Events - Inertia.js

// Handle the error yourself


})

This event will not fire for XHR requests that receive 400 and 500 level responses or
for non-Inertia responses, as these situations are handled in other ways by Inertia.
Please consult the error handling documentation for more information.

Finish

The finish event fires after an XHR request has completed for both "successful"
and "unsuccessful" responses. This event is useful for hiding loading indicators.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.on('finish', (event) => {


NProgress.done()
})

The finish event is not cancelable.

Navigate

The navigate event fires on successful page visits, as well as when navigating
through history.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/events 9/10
3/25/24, 10:22 AM Events - Inertia.js

import { router } from '@inertiajs/vue3'

router.on('navigate', (event) => {


console.log(`Navigated to ${event.detail.page.url}`)
})

The navigate event is not cancelable.

Event callbacks

In addition to the global events described throughout this page, Inertia also
provides a number of event callbacks that fire when manually making Inertia visits.

https://inertiajs.com/events 10/10
3/25/24, 10:22 AM Testing - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Testing

There are many different ways to test an Inertia application. This page provides a
quick overview of the tools available.

End-to-end tests

One popular approach to testing your JavaScript page components is to use an


end-to-end testing tool like Cypress or Laravel Dusk. These are browser
automation tools that allow you to run real simulations of your app in the browser.
These tests are known to be slower; however, since they test your application at
the same layer as your end users, they can provide a lot of confidence that your
app is working correctly. And, since these tests are run in the browser, your
JavaScript code is actually executed and tested as well.

Client-side unit tests

Another approach to testing your page components is using a client-side unit


testing framework, such as Jest or Mocha. This approach allows you to test your
JavaScript page components in isolation using Node.js.

https://inertiajs.com/testing 1/6
3/25/24, 10:22 AM Testing - Inertia.js

Endpoint tests

In addition to testing your JavaScript page components, you will likely want to
also test the Inertia responses that are returned by your server-side framework. A
popular approach to doing this is using endpoint tests, where you make requests
to your application and examine the responses. Laravel provides tooling for
executing these types of tests.

However, to make this process even easier, Inertia's Laravel adapter provides
additional HTTP testing tools. Let's take a look at an example.

use Inertia\Testing\AssertableInertia as Assert;

class PodcastsControllerTest extends TestCase


{
public function test_can_view_podcast()
{
$this->get('/podcasts/41')
->assertInertia(fn (Assert $page) => $page
->component('Podcasts/Show')
->has('podcast', fn (Assert $page) => $page
->where('id', $podcast->id)
->where('subject', 'The Laravel Podcast')
->where('description', 'The Laravel Podcast brings you Laravel and P
->has('seasons', 4)
->has('seasons.4.episodes', 21)
->has('host', fn (Assert $page) => $page
->where('id', 1)
->where('name', 'Matt Stauffer')
)
->has('subscribers', 7, fn (Assert $page) => $page
->where('id', 2)
->where('name', 'Claudio Dekker')
->where('platform', 'Apple Podcasts')
->etc()
->missing('email')
->missing('password')
)
)
);

https://inertiajs.com/testing 2/6
3/25/24, 10:22 AM Testing - Inertia.js

}
}

As you can see in the example above, you may use these assertion methods to
assert against the content of the data provided to the Inertia response. In
addition, you may assert that array data has a given length as well as scope your
assertions.

Let's dig into the available assertions in detail. First, to assert that the Inertia
response has a property, you may use the has method. You can think of this
method as being similar to PHP's isset function.

$response->assertInertia(fn (Assert $page) => $page


// Checking a root-level property...
->has('podcast')

// Checking nested properties using "dot" notation...


->has('podcast.id')
);

To assert that an Inertia property has a specified amount of items, you may
provide the expected size as the second argument to the has method.

$response->assertInertia(fn (Assert $page) => $page


// Checking if a root-level property has 7 items...
->has('podcasts', 7)

// Checking nested properties using "dot" notation...


->has('podcast.subscribers', 7)
);

The has method may also be used to scope properties in order to lessen repetition
when asserting against nested properties.
https://inertiajs.com/testing 3/6
3/25/24, 10:22 AM Testing - Inertia.js

$response->assertInertia(fn (Assert $page) => $page


// Creating a single-level property scope...
->has('message', fn (Assert $page) => $page
// We can now continue chaining methods...
->has('subject')
->has('comments', 5)

// And can even create a deeper scope using "dot" notation...


->has('comments.0', fn (Assert $page) => $page
->has('body')
->has('files', 1)
->has('files.0', fn (Assert $page) => $page
->has('url')
)
)
)
);

When scoping into Inertia properties that are arrays or collections, you may also
assert that a specified number of items are present in addition to scoping into the
first item.

$response->assertInertia(fn (Assert $page) => $page


// Assert that there are 5 comments and automatically scope into the first comment..
->has('comments', 5, fn (Assert $page) => $page
->has('body')
// ...
)
);

To assert that an Inertia property has an expected value, you may use the where

assertion.

$response->assertInertia(fn (Assert $page) => $page


->has('message', fn (Assert $page) => $page
// Assert that the subject prop matches the given message...
https://inertiajs.com/testing 4/6
3/25/24, 10:22 AM Testing - Inertia.js

->where('subject', 'This is an example message')

// Or, assert against deeply nested values...


->where('comments.0.files.0.name', 'example-attachment.pdf')
)
);

Inertia's testing methods will automatically fail when you haven't interacted with at
least one of the props in a scope. While this is generally useful, you might run into
situations where you're working with unreliable data (such as from an external
feed), or with data that you really don't want interact with in order to keep your
test simple. For these situations, the etc method exists.

$response->assertInertia(fn (Assert $page) => $page


->has('message', fn (Assert $page) => $page
->has('subject')
->has('comments')
->etc()
)
);

The missing method is the exact opposite of the has method, ensuring that the
property does not exist. This method makes a great companion to the etc

method.

$response->assertInertia(fn (Assert $page) => $page


->has('message', fn (Assert $page) => $page
->has('subject')
->missing('published_at')
->etc()
)
);

https://inertiajs.com/testing 5/6
3/25/24, 10:22 AM Testing - Inertia.js

https://inertiajs.com/testing 6/6
3/25/24, 10:22 AM Partial reloads - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Partial reloads

When making visits to the same page you are already on, it's not always
necessary to re-fetch all of the page's data from the server. In fact, selecting only
a subset of the data can be a helpful performance optimization if it's acceptable
that some page data becomes stale. Inertia makes this possible via its "partial
reload" feature.

As an example, consider a "user index" page that includes a list of users, as well as
an option to filter the users by their company. On the first request to the page,
both the users and companies props are passed to the page component. However,
on subsequent visits to the same page (maybe to filter the users), you can request
only the users data from the server without requesting the companies data. Inertia
will then automatically merge the partial data returned from the server with the
data it already has in memory client-side.

Partial reloads only work for visits made to the same page component.

Making partial visits

https://inertiajs.com/partial-reloads 1/3
3/25/24, 10:22 AM Partial reloads - Inertia.js

To perform a partial reload, use the only property to specify which data the server
should return. This option should be an array of keys which correspond to the keys
of the props.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.visit(url, {
only: ['users'],
})

Since partial reloads can only be made to the same page component the user is
already on, it almost always makes sense to just use the router.reload() method,
which automatically uses the current URL.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.reload({ only: ['users'] })

It's also possible to perform partial reloads with Inertia links using the only

property.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/users?active=true" :only="['users']">Show active</Link>

https://inertiajs.com/partial-reloads 2/3
3/25/24, 10:22 AM Partial reloads - Inertia.js

Lazy data evaluation

For partial reloads to be most effective, be sure to also use lazy data evaluation
when returning props from your server-side routes or controllers. This can be
accomplished by wrapping all optional page data in a closure.

When Inertia performs a request, it will determine which data is required and only
then will it evaluate the closure. This can significantly increase the performance of
pages that contain a lot of optional data.

return Inertia::render('Users/Index', [
// ALWAYS included on first visit...
// OPTIONALLY included on partial reloads...
// ALWAYS evaluated...
'users' => User::get(),

// ALWAYS included on first visit...


// OPTIONALLY included on partial reloads...
// ONLY evaluated when needed...
'users' => fn () => User::get(),

// NEVER included on first visit...


// OPTIONALLY included on partial reloads...
// ONLY evaluated when needed...
'users' => Inertia::lazy(fn () => User::get()),
]);

https://inertiajs.com/partial-reloads 3/3
3/25/24, 10:22 AM Scroll management - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Scroll management

Scroll resetting

When navigating between pages, Inertia mimics default browser behaviour by


automatically resetting the scroll position of the document body (as well as any
scroll regions you've defined) back to the top. In addition, Inertia keeps track of the
scroll position of each page and automatically restores that scroll position as you
navigate forward and back in history.

Scroll preservation

Sometimes it's desirable to prevent the default scroll resetting behavior when
making visits. You can disable this behaviour using the preserveScroll option when
manually making visits.

router.visit(url, { preserveScroll: true })

You can also lazily evaluate the preserveScroll option based on the server's
response by providing a callback to the option.

https://inertiajs.com/scroll-management 1/2
3/25/24, 10:22 AM Scroll management - Inertia.js

router.post('/users', data, {
preserveScroll: (page) => Object.keys(page.props.errors).length,
})

You can also preserve the scroll position when using Inertia links using the
preserve-scroll attribute.

Vue 2 Vue 3 React Svelte

import { Link } from '@inertiajs/vue3'

<Link href="/" preserve-scroll>Home</Link>

Scroll regions

If your app doesn't use document body scrolling, but instead has scrollable
elements (using the overflow CSS property), scroll resetting will not work. In these
situations, you must tell Inertia which scrollable elements to manage by adding a
scroll-region attribute to the element.

<div class="overflow-y-auto" scroll-region>


<!-- Your page content -->
</div>

https://inertiajs.com/scroll-management 2/2
3/25/24, 10:22 AM Authentication - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Authentication

One of the benefits of using Inertia is that you don't need a special authentication
system such as OAuth to connect to your data provider (API). Also, since your data
is provided via your controllers, and housed on the same domain as your
JavaScript components, you don't have to worry about setting up CORS.

Rather, when using Inertia, you can simply use whatever authentication system
your server-side framework ships with. Typically, this will be a session based
authentication system such as the authentication system included with Laravel.

Laravel's starter kits, Breeze and Jetstream, provide out-of-the-box scaffolding for
new Inertia applications, including authentication.

https://inertiajs.com/authentication 1/1
3/25/24, 10:22 AM Authorization - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Authorization

When using Inertia, authorization is best handled server-side in your application's


authorization policies. However, you may be wondering how to perform checks
against your authorization policies from within your Inertia page components since
you won't have access to your framework's server-side helpers.

The simplest approach to solving this problem is to pass the results of your
authorization checks as props to your page components.

class UsersController extends Controller


{
public function index()
{
return Inertia::render('Users/Index', [
'can' => [
'create_user' => Auth::user()->can('create', User::class),
],
'users' => User::all()->map(function ($user) {
return [
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'email' => $user->email,
'can' => [
'edit_user' => Auth::user()->can('edit', $user),
]
];
}),

https://inertiajs.com/authorization 1/2
3/25/24, 10:22 AM Authorization - Inertia.js

]);
}
}

https://inertiajs.com/authorization 2/2
3/25/24, 10:22 AM CSRF protection - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

CSRF protection

Making requests

Laravel automatically includes the proper CSRF token when making requests via
Inertia or Axios. However, if you're using Laravel, be sure to omit the csrf-token meta
tag from your project, as this will prevent the CSRF token from refreshing properly.

If your server-side framework includes cross-site request forgery (CSRF) protection,


you'll need to ensure that each Inertia requests includes the necessary CSRF token
for POST , PUT , PATCH , and DELETE requests.

Of course, as already discussed, some server-side frameworks such as Laravel


automatically handle the inclusion of the CSRF token when making requests.
Therefore, no additional configuration is required when using one of these
frameworks.

However, if you need to handle CSRF protection manually, one approach is to


include the CSRF token as a prop on every response. You can then use the token
when making Inertia requests.

https://inertiajs.com/csrf-protection 1/4
3/25/24, 10:22 AM CSRF protection - Inertia.js

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

router.post('/users', {
name: this.name,
email: this.email,
_token: this.$page.props.csrf_token,
})

You can even use Inertia's shared data functionality to automatically include the
csrf_token with each response.

However, a better approach is to use the CSRF functionality already built into
axios for this. Axios is the HTTP library that Inertia uses under the hood.

Axios automatically checks for the existence of an XSRF-TOKEN cookie. If it's present,
it will then include the token in an X-XSRF-TOKEN header for any requests it makes.

The easiest way to implement this is using server-side middleware. Simply include
the XSRF-TOKEN cookie on each response, and then verify the token using the
X-XSRF-TOKEN header sent in the requests from axios.

Handling mismatches

When a CSRF token mismatch occurs, your server-side framework will likely throw
an exception that results in an error response. For example, when using Laravel, a
TokenMismatchException is thrown which results in a 419 error page. Since that isn't a
valid Inertia response, the error is shown in a modal.

https://inertiajs.com/csrf-protection 2/4
3/25/24, 10:22 AM CSRF protection - Inertia.js

0:00 / 0:03

Obviously, this isn't a great user experience. A better way to handle these errors is
to return a redirect back to the previous page, along with a flash message that
the page expired. This will result in a valid Inertia response with the flash message
available as a prop which you can then display to the user. Of course, you'll need
to share your flash messages with Inertia for this to work.

When using Laravel, you may modify your application's exception handler to
automatically redirect the user back to the page they were previously on while
flashing a message to the session. To accomplish this, you may use the respond
exception method in your application's bootstrap/app.php file.

use Symfony\Component\HttpFoundation\Response;

->withExceptions(function (Exceptions $exceptions) {


$exceptions->respond(function (Response $response) {
if ($response->getStatusCode() === 419) {
return back()->with([
'message' => 'The page expired, please try again.',
https://inertiajs.com/csrf-protection 3/4
3/25/24, 10:22 AM CSRF protection - Inertia.js

]);
}

return $response;
});
});

The end result is a much better experience for your users. Instead of seeing the
error modal, the user is instead presented with a message that the page "expired"
and are asked to try again.

0:00 / 0:02

https://inertiajs.com/csrf-protection 4/4
3/25/24, 10:22 AM Error handling - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Error handling

Development

One of the advantages to working with a robust server-side framework is the


built-in exception handling you get for free. For example, Laravel ships with
Ignition, a beautiful error reporting tool which displays a nicely formatted stack
trace in local development.

The challenge is, if you're making an XHR request (which Inertia does) and you hit a
server-side error, you're typically left digging through the network tab in your
browser's devtools to diagnose the problem.

Inertia solves this issue by showing all non-Inertia responses in a modal. This
means you get the same beautiful error-reporting you're accustomed to, even
though you've made that request over XHR.

https://inertiajs.com/error-handling 1/4
3/25/24, 10:22 AM Error handling - Inertia.js

Loading…

Production

In production you will want to return a proper Inertia error response instead of
relying on the modal-driven error reporting that is present during development. To
accomplish this, you'll need to update your framework's default exception handler
to return a custom error page.

When building Laravel applications, you can accomplish this by using the respond

exception method in your application's bootstrap/app.php file.

use Illuminate\Http\Request;
use Illuminate\Http\Response;
https://inertiajs.com/error-handling 2/4
3/25/24, 10:22 AM Error handling - Inertia.js

use Inertia\Inertia;

->withExceptions(function (Exceptions $exceptions) {


$exceptions->respond(function (Response $response, Throwable $exception, Request $re
if (! app()->environment(['local', 'testing']) && in_array($response->status(),
return Inertia::render('Error', ['status' => $response->status()])
->toResponse($request)
->setStatusCode($response->status());
} elseif ($response->status() === 419) {
return back()->with([
'message' => 'The page expired, please try again.',
]);
}

return $response;
});
})

You may have noticed we're returning an Error page component in the example
above. You'll need to actually create this component, which will serve as the
generic error page for your application. Here's an example error component you
can use as a starting point.

Vue 2 Vue 3 React Svelte

<script setup>
import { computed } from 'vue'

const props = defineProps({ status: Number })

const title = computed(() => {


return {
503: '503: Service Unavailable',
500: '500: Server Error',
404: '404: Page Not Found',
403: '403: Forbidden',
}[props.status]
})

const description = computed(() => {

https://inertiajs.com/error-handling 3/4
3/25/24, 10:22 AM Error handling - Inertia.js

return {
503: 'Sorry, we are doing some maintenance. Please check back soon.',
500: 'Whoops, something went wrong on our servers.',
404: 'Sorry, the page you are looking for could not be found.',
403: 'Sorry, you are forbidden from accessing this page.',
}[props.status]
})
</script>

<template>
<div>
<H1>{{ title }}</H1>
<div>{{ description }}</div>
</div>
</template>

https://inertiajs.com/error-handling 4/4
3/25/24, 10:22 AM Asset versioning - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Asset versioning

One common challenge when building single-page apps is refreshing site assets
when they've been changed. Thankfully, Inertia makes this easy by optionally
tracking the current version of your site assets. When an asset changes, Inertia will
automatically make a full page visit instead of a XHR visit on the next request.

Configuration

To enable automatic asset refreshing, you need to tell Inertia the current version of
your assets. This can be any arbitrary string (letters, numbers, or a file hash), as
long as it changes when your assets have been updated.

Typically, your application's asset version can be specified within the version

method of the Inertia HandleInertiaRequests middleware.

class HandleInertiaRequests extends Middleware


{
public function version(Request $request)
{
return parent::version($request);
}
}

https://inertiajs.com/asset-versioning 1/2
3/25/24, 10:22 AM Asset versioning - Inertia.js

The HandleInertiaRequests middleware provides a sensible default for Laravel applications,


which uses either a hash of the "app.asset_url" configuration value or the "mix-manifest.json" file.
When using Vite, Inertia will use a hash of the "build/manifest.json" file.

Alternatively, the asset version can be provided manually using the


Inertia::version() method.

use Inertia\Inertia;

Inertia::version($version);
Inertia::version(fn () => $version); // Lazily...

Cache busting

Asset refreshing in Inertia works on the assumption that a hard page visit will
trigger your assets to reload. However, Inertia doesn't actually do anything to force
this. Typically this is done with some form of cache busting. For example,
appending a version query parameter to the end of your asset URLs.

If you're using Laravel Mix, you can do this automatically by enabling versioning in
your webpack.mix.js file. When using Laravel's Vite integration, asset versioning is
done automatically.

https://inertiajs.com/asset-versioning 2/2
3/25/24, 10:22 AM Progress indicators - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Progress indicators

Since Inertia requests are made via XHR, there would typically not be a browser
loading indicator when navigating from one page to another. To solve this, Inertia
displays a progress indicator at the top of the page whenever you make an Inertia
visit.

Of course, if you prefer, you can disable Inertia's default loading indicator and
provide your own custom implementation. We'll discuss both approaches below.

Default

Inertia's default progress indicator is a light-weight wrapper around the NProgress


library. You can customize it via the progress property of the createInertiaApp()

function.

createInertiaApp({
progress: {
// The delay after which the progress bar will appear, in milliseconds...
delay: 250,

// The color of the progress bar...


color: '#29d',

https://inertiajs.com/progress-indicators 1/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

// Whether to include the default NProgress styles...


includeCSS: true,

// Whether the NProgress spinner will be shown...


showSpinner: false,
},
// ...
})

You can disable Inertia's default loading indicator by setting the progress property
to false .

createInertiaApp({
progress: false,
// ...
})

Custom

It's also possible to setup your own custom page loading indicators using Inertia
events. Let's explore how to do this using the NProgress library as an example.

First, disable Inertia's default loading indicator.

createInertiaApp({
progress: false,
// ...
})

Next, install the NProgress library.

https://inertiajs.com/progress-indicators 2/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

npm install nprogress

After installation, you'll need to add the NProgress styles to your project. You can
do this using a CDN hosted copy of the styles.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/npro

Next, import both NProgress and the Inertia router into your application.

Vue 2 Vue 3 React Svelte

import NProgress from 'nprogress'


import { router } from '@inertiajs/vue3'

Next, let's add a start event listener. We'll use this listener to show the progress
bar when a new Inertia visit begins.

router.on('start', () => NProgress.start())

Then, let's add a finish event listener to hide the progress bar when the page visit
finishes.

router.on('finish', () => NProgress.done())

https://inertiajs.com/progress-indicators 3/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

That's it! Now, as you navigate from one page to another, the progress bar will be
added and removed from the page.

Handling cancelled visits

While this custom progress implementation works great for page visits that finish
properly, it would be nice to handle cancelled visits as well. First, for interrupted
visits (those that get cancelled as a result of a new visit), the progress bar should
simply be reset back to the start position. Second, for manually cancelled visits,
the progress bar should be immediately removed from the page.

We can accomplish this by inspecting the event.detail.visit object that's


provided to the finish event.

router.on('finish', (event) => {


if (event.detail.visit.completed) {
NProgress.done()
} else if (event.detail.visit.interrupted) {
NProgress.set(0)
} else if (event.detail.visit.cancelled) {
NProgress.done()
NProgress.remove()
}
})

File upload progress

Let's take this a step further. When files are being uploaded, it would be great to
update the loading indicator to reflect the upload progress. This can be done
using the progress event.

https://inertiajs.com/progress-indicators 4/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

router.on('progress', (event) => {


if (event.detail.progress.percentage) {
NProgress.set((event.detail.progress.percentage / 100) * 0.9)
}
})

Now, instead of the progress bar "trickling" while the files are being uploaded, it will
actually update it's position based on the progress of the request. We limit the
progress here to 90%, since we still need to wait for a response from the server.

Loading indicator delay

The last thing we're going to implement is a loading indicator delay. It's often
preferable to delay showing the loading indicator until a request has taken longer
than 250-500 milliseconds. This prevents the loading indicator from appearing
constantly on quick page visits, which can be visually distracting.

To implement the delay behaviour, we'll use the setTimeout and clearTimeout

functions. Let's start by defining a variable to keep track of the timeout.

let timeout = null

Next, let's update the start event listener to start a new timeout that will show the
progress bar after 250 milliseconds.

router.on('start', () => {
timeout = setTimeout(() => NProgress.start(), 250)
})

https://inertiajs.com/progress-indicators 5/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

Next, we'll update the finish event listener to clear any existing timeouts in the
event that the page visit finishes before the timeout does.

router.on('finish', (event) => {


clearTimeout(timeout)
// ...
})

In the finish event listener, we need to determine if the progress bar has actually
started displaying progress, otherwise we'll inadvertently cause it to show before
the timeout has finished.

router.on('finish', (event) => {


clearTimeout(timeout)
if (!NProgress.isStarted()) {
return
}
// ...
})

And, finally, we need to do the same check in the progress event listener.

router.on('progress', event => {


if (!NProgress.isStarted()) {
return
}
// ...
}

That's it, you now have a beautiful custom page loading indicator!

https://inertiajs.com/progress-indicators 6/7
3/25/24, 10:22 AM Progress indicators - Inertia.js

Complete example

For convenience, here is the full source code of the final version of our custom
loading indicator.

Vue 2 Vue 3 React Svelte

import NProgress from 'nprogress'


import { router } from '@inertiajs/vue3'

let timeout = null

router.on('start', () => {
timeout = setTimeout(() => NProgress.start(), 250)
})

router.on('progress', (event) => {


if (NProgress.isStarted() && event.detail.progress.percentage) {
NProgress.set((event.detail.progress.percentage / 100) * 0.9)
}
})

router.on('finish', (event) => {


clearTimeout(timeout)
if (!NProgress.isStarted()) {
return
} else if (event.detail.visit.completed) {
NProgress.done()
} else if (event.detail.visit.interrupted) {
NProgress.set(0)
} else if (event.detail.visit.cancelled) {
NProgress.done()
NProgress.remove()
}
})

https://inertiajs.com/progress-indicators 7/7
3/25/24, 10:22 AM Remembering state - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Remembering state

When navigating browser history, Inertia restores pages using prop data cached in
history state. However, Inertia does not restore local page component state since
this is beyond its reach. This can lead to outdated pages in your browser history.

For example, if a user partially completes a form, then navigates away, and then
returns back, the form will be reset and their work will be lost.

To mitigate this issue, you can tell Inertia which local component state to save in
the browser history.

Saving local state

To save local component state to the history state, use the remember feature to tell
Inertia which data it should remember.

Vue 2 Vue 3 React Svelte

import { useRemember } from '@inertiajs/vue3'

const form = useRemember({


first_name: null,

https://inertiajs.com/remembering-state 1/4
3/25/24, 10:22 AM Remembering state - Inertia.js

last_name: null,
})

Use the "useRemember" hook to tell Inertia which data it should remember.

Now, whenever your local form state changes, Inertia will automatically save this
data to the history state and will also restore it on history navigation.

Multiple components

If your page contains multiple components that use the remember functionality
provided by Inertia, you need to provide a unique key for each component so that
Inertia knows which data to restore to each component.

Vue 2 Vue 3 React Svelte

import { useRemember } from '@inertiajs/vue3'

const form = useRemember({


first_name: null,
last_name: null,
}, 'Users/Create')

Set a key as the second argument of useRemember().

If you have multiple instances of the same component on the page using the
remember functionality, be sure to also include a unique key for each component
instance, such as a model identifier.

Vue 2 Vue 3 React Svelte

https://inertiajs.com/remembering-state 2/4
3/25/24, 10:22 AM Remembering state - Inertia.js

import { useRemember } from '@inertiajs/vue3'

const props = defineProps({ user: Object })

const form = useRemember({


first_name: null,
last_name: null,
}, `Users/Edit:${props.user.id}`)

Set a dynamic key as the second argument of useRemember().

Form helper

If you're using the Inertia form helper, you can pass a unique form key as the first
argument when instantiating your form. This will cause the form data and errors to
automatically be remembered.

Vue 2 Vue 3 React Svelte

import { useForm } from '@inertiajs/vue3'

const form = useForm('CreateUser', data)


const form = useForm(`EditUser:${props.user.id}`, data)

Manually saving state

The remember property in Vue 2, and the useRemember hook in Vue 3, React, and
Svelte all watch for data changes and automatically save those changes to the
history state. Then, Inertia will restore the data on page load.

https://inertiajs.com/remembering-state 3/4
3/25/24, 10:22 AM Remembering state - Inertia.js

However, it's also possible to manage this manually using the underlying
remember() and restore() methods in Inertia.

Vue 2 Vue 3 React Svelte

import { router } from '@inertiajs/vue3'

// Save local component state to history state...


router.remember(data, 'my-key')

// Restore local component state from history state...


let data = router.restore('my-key')

https://inertiajs.com/remembering-state 4/4
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

🥳 Inertia.js v1.0 has been released! Upgrade guide Legacy docs

Server-side Rendering (SSR)

Server-side rendering pre-renders your JavaScript pages on the server, allowing


your visitors to receive fully rendered HTML when they visit your application. Since
fully rendered HTML is served by your application, it's also easier for search engines
to index your site.

Server-side rendering uses Node.js to render your pages in a background process;


therefore, Node must be available on your server for server-side rendering to function
properly.

Laravel starter kits

If you are using Laravel Breeze or Jetstream, you may install the starter kit's
scaffolding with Inertia SSR support pre-configured using the --ssr flag.

php artisan breeze:install react --ssr


php artisan breeze:install vue --ssr

https://inertiajs.com/server-side-rendering 1/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

Install dependencies

If you are not using a Laravel starter kit and would like to manually configure SSR,
we'll first install the additional dependencies required for server-side rendering.
This is only necessary for the Vue adapters, so you can skip this step if you're using
React or Svelte.

Vue 2 Vue 3 React Svelte

npm install @vue/server-renderer

Then, make sure you have the latest version of the Inertia Laravel adapter
installed.

composer require inertiajs/inertia-laravel

Add server entry-point

Next, we'll create a resources/js/ssr.js file within our Laravel project that will serve
as our SSR entry point.

touch resources/js/ssr.js

This file is going to look very similar to your resources/js/app.js file, except it's not
going to run in the browser, but rather in Node.js. Here's a complete example.

https://inertiajs.com/server-side-rendering 2/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

Vue 2 Vue 3 React Svelte

import { createInertiaApp } from '@inertiajs/vue3'


import createServer from '@inertiajs/vue3/server'
import { renderToString } from '@vue/server-renderer'
import { createSSRApp, h } from 'vue'

createServer(page =>
createInertiaApp({
page,
render: renderToString,
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
setup({ App, props, plugin }) {
return createSSRApp({
render: () => h(App, props),
}).use(plugin)
},
}),
)

When creating this file, be sure to add anything that's missing from your app.js file
that makes sense to run in SSR mode, such as plugins or custom mixins.

Setup Vite

Next, we need to update our Vite configuration to build our new ssr.js file. We
can do this by adding a ssr property to Laravel's Vite plugin configuration in our
vite.config.js file.

export default defineConfig({


plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],

https://inertiajs.com/server-side-rendering 3/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

+ ssr: 'resources/js/ssr.js',
refresh: true,
}),
// ...
],
})

Update npm script

Next, let's update the build script in our package.json file to also build our new
ssr.js file.

"scripts": {
"dev": "vite",
- "build": "vite build"
+ "build": "vite build && vite build --ssr"
},

Now you can build both your client-side and server-side bundles.

npm run build

Running the SSR server

Now that you have built both your client-side and server-side bundles, you should
be able run the Node-based Inertia SSR server using the following command.

php artisan inertia:start-ssr

https://inertiajs.com/server-side-rendering 4/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

With the server running, you should be able to access your app within the browser
with server-side rendering enabled. In fact, you should be able to disable
JavaScript entirely and still navigate around your application.

Client side hydration

Since your website is now being server-side rendered, you can instruct Vue to
"hydrate" the static markup and make it interactive instead of re-rendering all the
HTML that we just generated.

To enable client-side hydration in a Vue 3 app, update your app.js file to use
createSSRApp instead of createApp :

Vue 2 Vue 3 React Svelte

- import { createApp, h } from 'vue'


+ import { createSSRApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
setup({ el, App, props, plugin }) {
- createApp({ render: () => h(App, props) })
+ createSSRApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})

Deployment

https://inertiajs.com/server-side-rendering 5/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

When deploying your SSR enabled app to production, you'll need to build both the
client-side ( app.js ) and server-side bundles ( ssr.js ), and then run the SSR server
as a background process, typically using a process monitoring tool such as
Supervisor.

php artisan inertia:start-ssr

To stop the SSR server, for instance when you deploy a new version of your website,
you may utilize the inertia:stop-ssr Artisan command. Your process monitor (such
as Supervisor) should be responsible for automatically restarting the SSR server
after it has stopped.

php artisan inertia:stop-ssr

Laravel Forge

To run the SSR server on Forge, you should create a new daemon that runs
php artisan inertia:start-ssr from the root of your app. Or, you may utilize the
built-in Inertia integration from your Forge application's management dashboard.

Next, whenever you deploy your application, you can automatically restart the
SSR server by calling the php artisan inertia:stop-ssr command. This will stop the
existing SSR server, forcing a new one to be started by your process monitor.

Heroku

To run the SSR server on Heroku, update the web configuration in your Procfile to
run the SSR server before starting your web server.
https://inertiajs.com/server-side-rendering 6/7
3/25/24, 10:22 AM Server-side rendering (SSR) - Inertia.js

web: php artisan inertia:start-ssr & vendor/bin/heroku-php-apache2 public/

Note, you must have the heroku/nodejs buildpack installed in addition to the
heroku/php buildback for the SSR server to run.

https://inertiajs.com/server-side-rendering 7/7

You might also like