├── .gitignore
├── images
└── pingcrm.png
├── mp4
├── csrf-mismatch-modal.mp4
└── csrf-mismatch-warning.mp4
├── fonts
└── inter
│ ├── InterVariable.woff2
│ └── InterVariable-Italic.woff2
├── snippets
├── docs.css
├── client-specific.jsx
├── docs.js
├── vue-specific.jsx
├── react-specific.jsx
├── vue2-specific.jsx
├── vue3-specific.jsx
├── svelte-specific.jsx
├── svelte4-specific.jsx
├── svelte5-specific.jsx
├── current-code-tab.jsx
└── color-generator.jsx
├── favicon.svg
├── README.md
├── v2
├── security
│ ├── authentication.mdx
│ ├── authorization.mdx
│ ├── history-encryption.mdx
│ └── csrf-protection.mdx
├── getting-started
│ ├── index.mdx
│ ├── demo-application.mdx
│ └── upgrade-guide.mdx
├── core-concepts
│ ├── who-is-it-for.mdx
│ └── how-it-works.mdx
├── installation
│ ├── community-adapters.mdx
│ └── server-side-setup.mdx
├── the-basics
│ ├── redirects.mdx
│ ├── routing.mdx
│ ├── file-uploads.mdx
│ └── title-and-meta.mdx
├── advanced
│ ├── asset-versioning.mdx
│ ├── code-splitting.mdx
│ ├── scroll-management.mdx
│ └── error-handling.mdx
└── data-props
│ ├── polling.mdx
│ ├── shared-data.mdx
│ ├── once-props.mdx
│ ├── deferred-props.mdx
│ ├── merging-props.mdx
│ ├── remembering-state.mdx
│ ├── partial-reloads.mdx
│ └── flash-data.mdx
├── style.css
├── assets
└── svelte.svg
├── v1
├── advanced
│ ├── authentication.mdx
│ ├── authorization.mdx
│ ├── asset-versioning.mdx
│ ├── scroll-management.mdx
│ ├── csrf-protection.mdx
│ ├── error-handling.mdx
│ ├── testing.mdx
│ ├── partial-reloads.mdx
│ └── remembering-state.mdx
├── getting-started
│ ├── index.mdx
│ └── demo-application.mdx
├── core-concepts
│ ├── who-is-it-for.mdx
│ ├── how-it-works.mdx
│ └── the-protocol.mdx
├── the-basics
│ ├── responses.mdx
│ ├── redirects.mdx
│ ├── routing.mdx
│ ├── file-uploads.mdx
│ └── shared-data.mdx
└── installation
│ ├── server-side-setup.mdx
│ └── client-side-setup.mdx
├── LICENSE
└── logo
├── dark.svg
└── light.svg
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/images/pingcrm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilanboy/docs/main/images/pingcrm.png
--------------------------------------------------------------------------------
/mp4/csrf-mismatch-modal.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilanboy/docs/main/mp4/csrf-mismatch-modal.mp4
--------------------------------------------------------------------------------
/mp4/csrf-mismatch-warning.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilanboy/docs/main/mp4/csrf-mismatch-warning.mp4
--------------------------------------------------------------------------------
/fonts/inter/InterVariable.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilanboy/docs/main/fonts/inter/InterVariable.woff2
--------------------------------------------------------------------------------
/snippets/docs.css:
--------------------------------------------------------------------------------
1 | svg[style*="regular/s.svg"] {
2 | mask-image: url("/docs/assets/svelte.svg") !important;
3 | }
4 |
--------------------------------------------------------------------------------
/fonts/inter/InterVariable-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yilanboy/docs/main/fonts/inter/InterVariable-Italic.woff2
--------------------------------------------------------------------------------
/snippets/client-specific.jsx:
--------------------------------------------------------------------------------
1 | export const ClientSpecific = ({ children }) => {
2 | // What's this you ask? It's me getting around some mintlify wildness
3 | // I don't know why this works, but it does. Mintlify you crazy.
4 | const [nada, setNada] = useState();
5 |
6 | return children;
7 | };
8 |
--------------------------------------------------------------------------------
/snippets/docs.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | const originalSetItem = localStorage.setItem;
3 |
4 | localStorage.setItem = function (key, value) {
5 | const event = new CustomEvent("localStorageUpdate", {
6 | detail: { key, value },
7 | });
8 |
9 | window.dispatchEvent(event);
10 |
11 | originalSetItem.call(this, key, value);
12 | };
13 | })();
14 |
--------------------------------------------------------------------------------
/favicon.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Development
2 |
3 | Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command:
4 |
5 | ```
6 | npm i -g mint
7 | ```
8 |
9 | Run the following command at the root of your documentation, where your `docs.json` is located:
10 |
11 | ```
12 | mint dev
13 | ```
14 |
15 | View your local preview at `http://localhost:3000`.
16 |
17 | ### Resources
18 |
19 | - [Mintlify documentation](https://mintlify.com/docs)
20 |
--------------------------------------------------------------------------------
/snippets/vue-specific.jsx:
--------------------------------------------------------------------------------
1 | export const VueSpecific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "Vue") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/react-specific.jsx:
--------------------------------------------------------------------------------
1 | export const ReactSpecific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "React") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/vue2-specific.jsx:
--------------------------------------------------------------------------------
1 | export const Vue2Specific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "Vue 2") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/vue3-specific.jsx:
--------------------------------------------------------------------------------
1 | export const Vue3Specific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "Vue 3") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/svelte-specific.jsx:
--------------------------------------------------------------------------------
1 | export const SvelteSpecific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (!code?.includes("Svelte")) {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/svelte4-specific.jsx:
--------------------------------------------------------------------------------
1 | export const Svelte4Specific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "Svelte 4") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/svelte5-specific.jsx:
--------------------------------------------------------------------------------
1 | export const Svelte5Specific = ({ children }) => {
2 | const [code, setCode] = useState(
3 | localStorage.getItem("code")?.replace(/"/g, "") || null,
4 | );
5 |
6 | const callback = useCallback((event) => {
7 | if (event.detail.key === "code") {
8 | setCode(event.detail.value.replace(/"/g, ""));
9 | }
10 | }, []);
11 |
12 | useEffect(() => {
13 | window.addEventListener("storage", callback);
14 | window.addEventListener("localStorageUpdate", callback);
15 |
16 | return () => {
17 | window.removeEventListener("storage", callback);
18 | window.removeEventListener("localStorageUpdate", callback);
19 | };
20 | });
21 |
22 | if (code !== "Svelte 5") {
23 | return null;
24 | }
25 |
26 | return children;
27 | };
28 |
--------------------------------------------------------------------------------
/snippets/current-code-tab.jsx:
--------------------------------------------------------------------------------
1 | export const CurrentCodeTab = () => {
2 | const [code, setCode] = useState(() => {
3 | if (typeof window === "undefined") return null;
4 | return localStorage.getItem("code")?.replace(/"/g, "") || null;
5 | });
6 |
7 | const callback = useCallback((event) => {
8 | if (event.detail.key === "code") {
9 | setCode(event.detail.value.replace(/"/g, ""));
10 | }
11 | }, []);
12 |
13 | useEffect(() => {
14 | window.addEventListener("storage", callback);
15 | window.addEventListener("localStorageUpdate", callback);
16 |
17 | return () => {
18 | window.removeEventListener("storage", callback);
19 | window.removeEventListener("localStorageUpdate", callback);
20 | };
21 | });
22 |
23 | if (code?.includes("Svelte")) {
24 | return "Svelte";
25 | }
26 |
27 | return code;
28 | };
29 |
--------------------------------------------------------------------------------
/v2/security/authentication.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Authentication
3 | ---
4 |
5 | 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.
6 |
7 | 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.
8 |
9 |
16 | Laravel's starter kits provide out-of-the-box scaffolding for new Inertia applications, including authentication.
17 |
18 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400..500&display=swap");
2 | @import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@300..600&display=swap");
3 |
4 | body {
5 | font-family: "Instrument Sans";
6 | font-weight: 400;
7 | }
8 |
9 | h1,
10 | h2,
11 | h3,
12 | h4 {
13 | font-weight: 500 !important;
14 | letter-spacing: -0.025rem !important;
15 | }
16 |
17 | code,
18 | pre {
19 | font-family: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco,
20 | Consolas, "Liberation Mono", "Courier New", monospace;
21 | }
22 |
23 | b,
24 | strong,
25 | .font-semibold {
26 | font-weight: 500 !important;
27 | }
28 |
29 | .prose :where(a):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
30 | font-weight: 500 !important;
31 | color: rgb(var(--primary-light)) !important;
32 | }
33 |
34 | .codeblock-dark div:not(:last-child) {
35 | color: #fafafa;
36 | }
37 |
--------------------------------------------------------------------------------
/assets/svelte.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/v1/advanced/authentication.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Authentication
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | 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.
8 |
9 | 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.
10 |
11 |
18 | Laravel's starter kits provide out-of-the-box scaffolding for new Inertia applications, including authentication.
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Mintlify
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/v2/security/authorization.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Authorization
3 | ---
4 |
5 | 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.
6 |
7 | The simplest approach to solving this problem is to pass the results of your authorization checks as props to your page components.
8 |
9 | ```php
10 | class UsersController extends Controller
11 | {
12 | public function index()
13 | {
14 | return Inertia::render('Users/Index', [
15 | 'can' => [
16 | 'create_user' => Auth::user()->can('create', User::class),
17 | ],
18 | 'users' => User::all()->map(function ($user) {
19 | return [
20 | 'first_name' => $user->first_name,
21 | 'last_name' => $user->last_name,
22 | 'email' => $user->email,
23 | 'can' => [
24 | 'edit_user' => Auth::user()->can('edit', $user),
25 | ]
26 | ];
27 | }),
28 | ]);
29 | }
30 | }
31 | ```
--------------------------------------------------------------------------------
/v2/getting-started/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | ---
4 |
5 | Inertia is a new approach to building classic server-driven web apps. We call it the modern monolith.
6 |
7 | Inertia allows you to create fully client-side rendered, single-page apps, without the complexity that comes with modern SPAs. It does this by leveraging existing server-side patterns that you already love.
8 |
9 | Inertia has no client-side routing, nor does it require an API. Simply build controllers and page views like you've always done! Inertia works great with any backend framework, but it's fine-tuned for [Laravel](https://laravel.com).
10 |
11 | ## Not a Framework
12 |
13 | Inertia isn't a framework, nor is it a replacement for your existing server-side or client-side frameworks. Rather, it's designed to work with them. Think of Inertia as glue that connects the two. Inertia does this via adapters. We currently have three official client-side adapters (React, Vue, and Svelte) and three server-side adapters (Laravel, Rails, and Phoenix).
14 |
15 | ## Next Steps
16 |
17 | Want to learn a bit more before diving in? Check out the [who is it for](/v2/core-concepts/who-is-it-for) and [how it works](/v2/core-concepts/how-it-works) pages. Or, if you're ready to get started, jump right into the [installation instructions](/v2/installation/server-side-setup).
--------------------------------------------------------------------------------
/v1/advanced/authorization.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Authorization
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | 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.
8 |
9 | The simplest approach to solving this problem is to pass the results of your authorization checks as props to your page components.
10 |
11 | ```php
12 | class UsersController extends Controller
13 | {
14 | public function index()
15 | {
16 | return Inertia::render('Users/Index', [
17 | 'can' => [
18 | 'create_user' => Auth::user()->can('create', User::class),
19 | ],
20 | 'users' => User::all()->map(function ($user) {
21 | return [
22 | 'first_name' => $user->first_name,
23 | 'last_name' => $user->last_name,
24 | 'email' => $user->email,
25 | 'can' => [
26 | 'edit_user' => Auth::user()->can('edit', $user),
27 | ]
28 | ];
29 | }),
30 | ]);
31 | }
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/logo/dark.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/logo/light.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/v1/getting-started/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | Inertia is a new approach to building classic server-driven web apps. We call it the modern monolith.
8 |
9 | Inertia allows you to create fully client-side rendered, single-page apps, without the complexity that comes with modern SPAs. It does this by leveraging existing server-side patterns that you already love.
10 |
11 | Inertia has no client-side routing, nor does it require an API. Simply build controllers and page views like you've always done! Inertia works great with any backend framework, but it's fine-tuned for [Laravel](https://laravel.com).
12 |
13 | ## Not a Framework
14 |
15 | Inertia isn't a framework, nor is it a replacement for your existing server-side or client-side frameworks. Rather, it's designed to work with them. Think of Inertia as glue that connects the two. Inertia does this via adapters. We currently have three official client-side adapters (React, Vue, and Svelte) and three server-side adapters (Laravel, Rails, and Phoenix).
16 |
17 | ## Next Steps
18 |
19 | Want to learn a bit more before diving in? Check out the [who is it for](/v1/core-concepts/who-is-it-for) and [how it works](/v1/core-concepts/how-it-works) pages. Or, if you're ready to get started, jump right into the [installation instructions](/v1/installation/server-side-setup).
20 |
--------------------------------------------------------------------------------
/v2/core-concepts/who-is-it-for.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Who Is Inertia.js For?
3 | ---
4 |
5 | Inertia was crafted for development teams and solo hackers who typically build server-side rendered applications using frameworks like Laravel, Ruby on Rails, Django, or Phoenix. You're used to creating controllers, retrieving data from the database (via an ORM), and rendering views.
6 |
7 | 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.
8 |
9 | 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.
10 |
11 | > **Inertia empowers you to build a modern, JavaScript-based single-page application without the tiresome complexity.**
12 |
13 | 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.
14 |
15 | 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.
16 |
--------------------------------------------------------------------------------
/v1/getting-started/demo-application.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Demo Application
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | We've setup a demo app for Inertia.js called [Ping CRM](https://demo.inertiajs.com). This application is built using Laravel and Vue. You can find the source code on [GitHub](https://github.com/inertiajs/pingcrm).
8 |
9 | The Ping CRM demo is hosted on Heroku and the database is reset every hour. Please be respectful when editing data.
10 |
11 | [](https://demo.inertiajs.com)In addition to the Vue version of Ping CRM, we also maintain a Svelte version of the application, which you can find [on GitHub](https://github.com/inertiajs/pingcrm-svelte).
12 |
13 | ## Third Party
14 |
15 | Beyond our official demo app, Ping CRM has also been translated into numerous different languages and frameworks.
16 |
17 | - [Ruby on Rails/Vue](https://github.com/ledermann/pingcrm/) by Georg Ledermann
18 | - [Laravel/React](https://github.com/Landish/pingcrm-react) by Lado Lomidze
19 | - [Laravel/Svelte](https://github.com/zgabievi/pingcrm-svelte) by Zura Gabievi
20 | - [Laravel/Mithril.js](https://github.com/tbreuss/pingcrm-mithril) by Thomas Breuss
21 | - [Yii 2/Vue](https://github.com/tbreuss/pingcrm-yii2) by Thomas Breuss
22 | - [Symfony/Vue](https://github.com/aleksblendwerk/pingcrm-symfony) by Aleks Seltenreich
23 | - [Clojure/React](https://github.com/prestancedesign/pingcrm-clojure) by Michaël Salihi
24 |
--------------------------------------------------------------------------------
/v1/core-concepts/who-is-it-for.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Who Is Inertia.js For?
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | Inertia was crafted for development teams and solo hackers who typically build server-side rendered applications using frameworks like Laravel, Ruby on Rails, Django, or Phoenix. You're used to creating controllers, retrieving data from the database (via an ORM), and rendering views.
8 |
9 | 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.
10 |
11 | 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.
12 |
13 | **Inertia empowers you to build a modern, JavaScript-based single-page application without the tiresome complexity.**
14 |
15 | 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.
16 |
17 | 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.
18 |
--------------------------------------------------------------------------------
/v1/the-basics/responses.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Responses
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | ## Creating Responses
8 |
9 | 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](/v1/the-basics/pages) that you wish to render, as well as any props (data) for the page.
10 |
11 | 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.
12 |
13 | ```php
14 | use Inertia\Inertia;
15 |
16 | class EventsController extends Controller
17 | {
18 | public function show(Event $event)
19 | {
20 | return Inertia::render('Event/Show', [
21 | 'event' => $event->only(
22 | 'id',
23 | 'title',
24 | 'start_date',
25 | 'description'
26 | ),
27 | ]);
28 |
29 | // Alternatively, you can use the inertia() helper...
30 | return inertia('Event/Show', [
31 | 'event' => $event->only(
32 | 'id',
33 | 'title',
34 | 'start_date',
35 | 'description'
36 | ),
37 | ]);
38 | }
39 | }
40 | ```
41 |
42 | ```html
43 |
44 | ```
45 |
46 | ```php
47 | return Inertia::render('Event', ['event' => $event])
48 | ->withViewData(['meta' => $event->meta]);
49 | ```
50 |
51 | ```html
52 |
53 | ```
54 |
--------------------------------------------------------------------------------
/v2/getting-started/demo-application.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Demo Application
3 | ---
4 |
5 | We've setup a demo app for Inertia.js called [Ping CRM](https://demo.inertiajs.com). This application is built using Laravel and Vue. You can find the source code on [GitHub](https://github.com/inertiajs/pingcrm).
6 |
7 | The Ping CRM demo is hosted on Heroku and the database is reset every hour. Please be respectful when editing data.
8 |
9 |
10 | [](https://demo.inertiajs.com)
11 |
12 |
13 | In addition to the Vue version of Ping CRM, we also maintain a Svelte version of the application, which you can find [on GitHub](https://github.com/inertiajs/pingcrm-svelte).
14 |
15 | ## Third Party
16 |
17 | Beyond our official demo app, Ping CRM has also been translated into numerous different languages and frameworks.
18 |
19 | | Platform | Author |
20 | |:-------------------------------------|:---------------------|
21 | | [Clojure/React](https://github.com/prestancedesign/pingcrm-clojure) | Michaël Salihi |
22 | | [Echo/Vue](https://github.com/kohkimakimoto/pingcrm-echo) | Kohki Makimoto |
23 | | [Grails/Vue](https://github.com/matrei/pingcrm-grails) | Mattias Reichel |
24 | | [Laravel/React](https://github.com/Landish/pingcrm-react) | Lado Lomidze |
25 | | [Laravel/Mithril.js](https://github.com/tbreuss/pingcrm-mithril) | Thomas Breuss |
26 | | [Laravel/Svelte](https://github.com/zgabievi/pingcrm-svelte) | Zura Gabievi |
27 | | [Ruby on Rails/Vue](https://github.com/ledermann/pingcrm/) | Georg Ledermann |
28 | | [Symfony/Vue](https://github.com/aleksblendwerk/pingcrm-symfony) | Aleks Seltenreich |
29 | | [Yii 2/Vue](https://github.com/tbreuss/pingcrm-yii2) | Thomas Breuss |
30 |
--------------------------------------------------------------------------------
/v2/installation/community-adapters.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Community Adapters
3 | ---
4 |
5 | In addition to the officially supported [Laravel](https://laravel.com/) adapter, there are also
6 | numerous community built server-side adapters available:
7 |
8 | - [AdonisJS](https://docs.adonisjs.com/guides/inertia)
9 | - [ASP.NET](https://github.com/kapi2289/InertiaCore)
10 | - [CakePHP InertiaJS Plugin](https://github.com/CakeDC/cakephp-inertia)
11 | - [CakePHP](https://github.com/ishanvyas22/cakephp-inertiajs)
12 | - [CanJS](https://github.com/cherifGsoul/inertia-can)
13 | - [Clojure](https://github.com/prestancedesign/inertia-clojure)
14 | - [ColdBox](https://github.com/elpete/cbInertia)
15 | - [Django](https://pypi.org/project/inertia-django/)
16 | - [Echo](https://github.com/kohkimakimoto/inertia-echo)
17 | - [Flask](https://github.com/j0ack/flask-inertia)
18 | - [Go (gonertia)](https://github.com/romsar/gonertia)
19 | - [Go (inertia-go)](https://github.com/petaki/inertia-go)
20 | - [Grails](https://github.com/matrei/grails-inertia-plugin)
21 | - [Kirby CMS](https://github.com/tobimori/kirby-inertia)
22 | - [Mako](https://github.com/inventor96/inertia-mako/)
23 | - [Masonite](https://github.com/girardinsamuel/masonite-inertia/)
24 | - [Mithril.js](https://github.com/maicol07/inertia-mithril)
25 | - [NestJS](https://github.com/harisfi/nestjs-inertia)
26 | - [Oak](https://github.com/jcs224/oak_inertia)
27 | - [Phoenix](https://github.com/inertiajs/inertia-phoenix)
28 | - [PSR-15](https://github.com/cherifGsoul/inertia-psr15)
29 | - [Rails](https://github.com/inertiajs/inertia-rails)
30 | - [Rust](https://github.com/stuarth/inertia-rs)
31 | - [Rust](https://kaiofelps.github.io/inertia-rust/)
32 | - [Sails](https://github.com/sailscastshq/boring-stack/tree/main/packages/inertia-sails)
33 | - [Spring/Ktor](https://github.com/Inertia4J/inertia4j)
34 | - [Symfony](https://github.com/skipthedragon/inertia-bundle)
35 | - [WordPress](https://github.com/evo-mark/inertia-wordpress)
36 | - [Yii2](https://github.com/tbreuss/yii2-inertia)
37 |
--------------------------------------------------------------------------------
/v1/advanced/asset-versioning.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Asset Versioning
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | 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.
8 |
9 | ## Configuration
10 |
11 | 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.
12 |
13 | Typically, your application's asset version can be specified within the `version` method of the Inertia `HandleInertiaRequests` middleware.
14 |
15 | ```php
16 | class HandleInertiaRequests extends Middleware
17 | {
18 | public function version(Request $request)
19 | {
20 | return parent::version($request);
21 | }
22 | }
23 | ```
24 |
25 | Alternatively, the asset version can be provided manually using the `Inertia::version()` method.
26 |
27 | ```php
28 | use Inertia\Inertia;
29 |
30 | Inertia::version($version);
31 | Inertia::version(fn () => $version); // Lazily...
32 | ```
33 |
34 | ## Cache Busting
35 |
36 | 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.
37 |
38 | If you're using Laravel Mix, you can do this automatically by enabling [versioning](https://laravel.com/docs/mix#versioning-and-cache-busting) in your `webpack.mix.js` file. When using Laravel's Vite integration, asset versioning is done automatically.
39 |
--------------------------------------------------------------------------------
/v2/core-concepts/how-it-works.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: How It Works
3 | ---
4 |
5 | ## Use the Tools You Love
6 |
7 | 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.
8 |
9 | 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.
10 |
11 | ## Intercepting Requests
12 |
13 | 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.
14 |
15 | 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 `` 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()`.
16 |
17 | 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.
18 |
19 | **The end result is a silky smooth single-page experience.**
20 |
21 | To learn more about the nitty-gritty, technical details of how Inertia works under the hood, check out the [protocol page](/v2/core-concepts/the-protocol).
22 |
--------------------------------------------------------------------------------
/v2/the-basics/redirects.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Redirects
3 | ---
4 |
5 | When making a non-GET Inertia request manually or via a `` element, you should ensure that you always respond with a proper Inertia redirect response.
6 |
7 | 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.
8 |
9 | ```php
10 | class UsersController extends Controller
11 | {
12 | public function index()
13 | {
14 | return Inertia::render('Users/Index', [
15 | 'users' => User::all(),
16 | ]);
17 | }
18 |
19 | public function store(Request $request)
20 | {
21 | User::create(
22 | $request->validate([
23 | 'name' => ['required', 'max:50'],
24 | 'email' => ['required', 'max:50', 'email'],
25 | ])
26 | );
27 |
28 | return to_route('users.index');
29 | }
30 | }
31 | ```
32 |
33 | ## 303 Response Code
34 |
35 | 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.
36 |
37 | If you're using one of our official server-side adapters, all redirects will automatically be converted to `303` redirects.
38 |
39 | ## External Redirects
40 |
41 | 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.
42 |
43 | ```php
44 | return Inertia::location($url);
45 | ```
46 |
47 | 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.
48 |
--------------------------------------------------------------------------------
/v1/core-concepts/how-it-works.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: How It Works
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | 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.
8 |
9 | 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.
10 |
11 | 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.
12 |
13 | 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 `` 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()`.
14 |
15 | 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.
16 |
17 | **The end result is a silky smooth single-page experience.** 🎉
18 |
19 | To learn more about the nitty-gritty, technical details of how Inertia works under the hood, check out the [protocol page](/v1/core-concepts/the-protocol).
20 |
--------------------------------------------------------------------------------
/v1/the-basics/redirects.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Redirects
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | When making a non-GET Inertia request manually or via a `` element, you should ensure that you always respond with a proper Inertia redirect response.
8 |
9 | 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.
10 |
11 | ```php
12 | class UsersController extends Controller
13 | {
14 | public function index()
15 | {
16 | return Inertia::render('Users/Index', [
17 | 'users' => User::all(),
18 | ]);
19 | }
20 |
21 | public function store(Request $request)
22 | {
23 | User::create(
24 | $request->validate([
25 | 'name' => ['required', 'max:50'],
26 | 'email' => ['required', 'max:50', 'email'],
27 | ])
28 | );
29 |
30 | return to_route('users.index');
31 | }
32 | }
33 | ```
34 |
35 | ## 303 Response Code
36 |
37 | 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.
38 |
39 | If you're using one of our official server-side adapters, all redirects will automatically be converted to `303` redirects.
40 |
41 | ## External Redirects
42 |
43 | 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.
44 |
45 | ```php
46 | return Inertia::location($url);
47 | ```
48 |
49 | 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.
50 |
--------------------------------------------------------------------------------
/v1/the-basics/routing.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Routing
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | ## Defining Routes
8 |
9 | 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](/v1/the-basics/responses) from those routes.
10 |
11 | ## Shorthand Routes
12 |
13 | If you have a [page](/v1/the-basics/pages) 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.
14 |
15 | ```php
16 | Route::inertia('/about', 'About');
17 | ```
18 |
19 | ## Generating URLs
20 |
21 | 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.
22 |
23 | 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.
24 |
25 | ```php
26 | class UsersController extends Controller
27 | {
28 | public function index()
29 | {
30 | return Inertia::render('Users/Index', [
31 | 'users' => User::all()->map(function ($user) {
32 | return [
33 | 'id' => $user->id,
34 | 'name' => $user->name,
35 | 'email' => $user->email,
36 | 'edit_url' => route('users.edit', $user),
37 | ];
38 | }),
39 | 'create_url' => route('users.create'),
40 | ]);
41 | }
42 | }
43 | ```
44 |
45 | However, when using Laravel, the [Ziggy](https://github.com/tightenco/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](https://laravel.com/docs/starter-kits), Ziggy is already configured for you.
46 |
47 | 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.
48 |
49 |
50 |
51 | ```js Vue 2 icon="vuejs"
52 | Vue.prototype.$route = route
53 | ```
54 |
55 | ```js Vue 3 icon="vuejs"
56 | app.config.globalProperties.$route = route
57 | ```
58 |
59 |
60 |
61 | ```html
62 | Create User
63 | ```
64 |
--------------------------------------------------------------------------------
/v2/security/history-encryption.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: History Encryption
3 | ---
4 |
5 | Imagine a scenario where your user is authenticated, browses privileged information on your site, then logs out. If they press the back button, they can still see the privileged information that is stored in the window's history state. This is a security risk. To prevent this, Inertia.js provides a history encryption feature.
6 |
7 | ## How It Works
8 |
9 | When you instruct Inertia to encrypt your app's history, it uses the browser's built-in [`crypto` api ](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) to encrypt the current page's data before pushing it to the history state. We store the corresponding key in the browser's session storage. When the user navigates back to a page, we decrypt the data using the key stored in the session storage.
10 |
11 | Once you instruct Inertia to clear your history state, we simply clear the existing key from session storage roll a new one. If we attempt to decrypt the history state with the new key, it will fail and Inertia will make a fresh request back to your server for the page data.
12 |
13 | History encryption relies on `window.crypto.subtle` which is only available in secure environments (sites with SSL enabled).
14 |
15 | ## Opting in
16 |
17 | History encryption is an opt-in feature. There are several methods for enabling it:
18 |
19 | ### Global Encryption
20 |
21 | If you'd like to enable history encryption globally, set the `inertia.history.encrypt` config value to `true`.
22 |
23 | You are able to opt out of encryption on specific pages by calling the `Inertia::encryptHistory()`method before returning the response.
24 |
25 | ```php
26 | Inertia::encryptHistory(false);
27 | ```
28 |
29 | ### Per-request Encryption
30 |
31 | To encrypt the history of an individual request, simply call the `Inertia::encryptHistory()` method before returning the response.
32 |
33 | ```php
34 | Inertia::encryptHistory();
35 | ```
36 |
37 | ### Encrypt Middleware
38 |
39 | To encrypt a group of routes, you may use Inertia's included `EncryptHistory` middleware.
40 |
41 | ```php
42 | Route::middleware([Inertia\Middleware\EncryptHistory::class])->get('/', function() {
43 | //
44 | });
45 |
46 | Route::middleware(['inertia::encrypt'])->get('/', function() {
47 | //
48 | });
49 | ```
50 |
51 | ## Clearing History
52 |
53 | To clear the history state, you can call the `Inertia::clearHistory()` method before returning the response.
54 |
55 | ```php
56 | Inertia::clearHistory();
57 | ```
58 |
59 | Once the response has rendered on the client, the encryption key will be rotated, rendering the previous history state unreadable.
60 |
61 | You can also clear history on the client site by calling `router.clearHistory()`.
62 |
--------------------------------------------------------------------------------
/v2/advanced/asset-versioning.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Asset Versioning
3 | ---
4 |
5 | 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.
6 |
7 | ## Configuration
8 |
9 | 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.
10 |
11 | Typically, your application's asset version can be specified within the `version` method of the Inertia `HandleInertiaRequests` middleware.
12 |
13 | ```php
14 | class HandleInertiaRequests extends Middleware
15 | {
16 | public function version(Request $request)
17 | {
18 | return parent::version($request);
19 | }
20 | }
21 | ```
22 |
23 | Alternatively, the asset version can be provided manually using the `Inertia::version()` method.
24 |
25 | ```php
26 | use Inertia\Inertia;
27 |
28 | Inertia::version($version);
29 | Inertia::version(fn () => $version); // Lazily...
30 | ```
31 |
32 | ## Cache Busting
33 |
34 | 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.
35 |
36 | With Laravel's Vite integration, asset versioning is done automatically. If you're using Laravel Mix, you can do this automatically by enabling [versioning](https://laravel.com/docs/mix#versioning-and-cache-busting) in your `webpack.mix.js` file.
37 |
38 | ## Manual Refreshing
39 |
40 | If you want to take asset refreshing into your control, you can return a fixed value from the `version` method in the `HandleInertiaRequests` middleware. This disables Inertia's automatic asset versioning.
41 |
42 | For example, if you want to notify users when a new version of your frontend is available, you can still expose the actual asset version to the frontend by including it as [shared data](/v2/data-props/shared-data).
43 |
44 | ```php
45 | class HandleInertiaRequests extends Middleware
46 | {
47 | public function version(Request $request)
48 | {
49 | return null;
50 | }
51 |
52 | public function share(Request $request)
53 | {
54 | return array_merge(parent::share($request), [
55 | 'version' => parent::version($request),
56 | ]);
57 | }
58 | }
59 | ```
60 |
61 | On the frontend, you can watch the `version` property and show a notification when a new version is detected.
62 |
--------------------------------------------------------------------------------
/v2/advanced/code-splitting.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Code Splitting
3 | ---
4 |
5 | Code splitting breaks apart the various pages of your application into smaller bundles, which are then loaded on demand when visiting new pages. This can significantly reduce the size of the initial JavaScript bundle loaded by the browser, improving the time to first render.
6 |
7 | While code splitting is helpful for very large projects, it does require extra requests when visiting new pages. Generally speaking, if you're able to use a single bundle, your app is going to feel snappier.
8 |
9 | To enable code splitting, you will need to tweak the `resolve` callback in your `createInertiaApp()` configuration, and how you do this is different depending on which bundler you're using.
10 |
11 | ## Using Vite
12 |
13 | Vite enables code splitting (or lazy-loading as they call it) by default when using their `import.meta.glob()` function, so simply omit the `{ eager: true }` option, or set it to `false`, to disable eager loading.
14 |
15 |
16 |
17 | ```js Vue icon="vuejs"
18 | resolve: name => {
19 | const pages = import.meta.glob('./Pages/**/*.vue', { eager: true }) // [!code --:2]
20 | return pages[`./Pages/${name}.vue`]
21 | const pages = import.meta.glob('./Pages/**/*.vue') // [!code ++:2]
22 | return pages[`./Pages/${name}.vue`]()
23 | },
24 | ```
25 |
26 | ```js React icon="react"
27 | resolve: name => {
28 | const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true }) // [!code --:2]
29 | return pages[`./Pages/${name}.jsx`]
30 | const pages = import.meta.glob('./Pages/**/*.jsx') // [!code ++:2]
31 | return pages[`./Pages/${name}.jsx`]()
32 | },
33 | ```
34 |
35 | ```js Svelte icon="s"
36 | resolve: name => {
37 | const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true }) // [!code --:2]
38 | return pages[`./Pages/${name}.svelte`]
39 | const pages = import.meta.glob('./Pages/**/*.svelte') // [!code ++:2]
40 | return pages[`./Pages/${name}.svelte`]()
41 | },
42 | ```
43 |
44 |
45 |
46 | ## Using Webpack
47 |
48 | To use code splitting with Webpack, you will first need to enable [dynamic imports](https://github.com/tc39/proposal-dynamic-import) via a Babel plugin. Let's install it now.
49 |
50 | ```bash
51 | npm install @babel/plugin-syntax-dynamic-import
52 | ```
53 |
54 | Next, create a `.babelrc` file in your project with the following configuration:
55 |
56 | ```json
57 | {
58 | "plugins": ["@babel/plugin-syntax-dynamic-import"]
59 | }
60 | ```
61 |
62 | If you're using Laravel Mix, the dynamic imports Babel plugin is already installed and configured, and you can skip these steps. We recommend using Laravel Mix 6 or above, as there are known issues with older versions.
63 |
64 | Finally, update the `resolve` callback in your app's initialization code to use `import`instead of `require`.
65 |
66 |
67 |
68 | ```js Vue icon="vuejs"
69 | resolve: name => require(`./Pages/${name}`), // [!code --]
70 | resolve: name => import(`./Pages/${name}`), // [!code ++]
71 | ```
72 |
73 | ```js React icon="react"
74 | resolve: name => require(`./Pages/${name}`), // [!code --]
75 | resolve: name => import(`./Pages/${name}`), // [!code ++]
76 | ```
77 |
78 | ```js Svelte icon="s"
79 | resolve: name => require(`./Pages/${name}.svelte`), // [!code --]
80 | resolve: name => import(`./Pages/${name}.svelte`), // [!code ++]
81 | ```
82 |
83 |
84 |
85 | You should also consider using cache busting to force browsers to load the latest version of your assets. To accomplish this, add the following configuration to your webpack configuration file.
86 |
87 | ```js
88 | output: {
89 | chunkFilename: 'js/[name].js?id=[chunkhash]',
90 | }
91 | ```
92 |
--------------------------------------------------------------------------------
/v1/installation/server-side-setup.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Server-side Setup
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | The first step when installing Inertia is to configure your server-side framework. Inertia maintains an official server-side adapter for [Laravel](https://laravel.com/). For other frameworks, please see the [community adapters](/community-adapters).
8 |
9 | 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.
10 |
11 | ## Laravel Starter Kits
12 |
13 | Laravel's [starter kits](https://laravel.com/docs/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.
14 |
15 | ## Install Dependencies
16 |
17 | First, install the Inertia server-side adapter using the Composer package manager.
18 |
19 | ```bash
20 | composer require inertiajs/inertia-laravel
21 | ```
22 |
23 | ## Root Template
24 |
25 | 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 `
` in which to boot your JavaScript application.
26 |
27 | ```blade
28 |
29 |
30 |
31 |
32 | @vite('resources/js/app.js')
33 | @inertiaHead
34 |
35 |
36 | @inertia
37 |
38 |
39 | ```
40 |
41 | This template should include your assets, as well as the `@inertia` and `@inertiaHead`directives.
42 |
43 | 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.
44 |
45 | ## Middleware
46 |
47 | 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.
48 |
49 | ```sh
50 | php artisan inertia:middleware
51 | ```
52 |
53 | Once the middleware has been published, append the `HandleInertiaRequests` middleware to the `web` middleware group in your application's `bootstrap/app.php` file.
54 |
55 | ```php
56 | use App\Http\Middleware\HandleInertiaRequests;
57 |
58 | ->withMiddleware(function (Middleware $middleware) {
59 | $middleware->web(append: [
60 | HandleInertiaRequests::class,
61 | ]);
62 | })
63 | ```
64 |
65 | This middleware provides a `version()` method for setting your [asset version](/v1/advanced/asset-versioning), as well as a `share()` method for defining [shared data](/v1/the-basics/shared-data).
66 |
67 | ## Creating Responses
68 |
69 | That's it, you're all ready to go server-side! Now you're ready to start creating Inertia [pages](/v1/the-basics/pages) and rendering them via [responses](/v1/the-basics/responses).
70 |
71 | ```php
72 | use Inertia\Inertia;
73 |
74 | class EventsController extends Controller
75 | {
76 | public function show(Event $event)
77 | {
78 | return Inertia::render('Event/Show', [
79 | 'event' => $event->only(
80 | 'id',
81 | 'title',
82 | 'start_date',
83 | 'description'
84 | ),
85 | ]);
86 | }
87 | }
88 | ```
89 |
--------------------------------------------------------------------------------
/v2/getting-started/upgrade-guide.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Upgrade Guide for v2.0
3 | ---
4 |
5 | You can find the legacy docs for Inertia.js v1.0 at [inertiajs.com/docs/v1](/v1).
6 |
7 | ## What's New
8 |
9 | Inertia.js v2.0 is a huge step forward for Inertia! The core library has been completely rewritten to architecturally support asynchronous requests, enabling a whole set of new features, including:
10 |
11 |
12 |
13 | Keep data fresh by automatically polling the server at a specified interval.
14 |
15 |
16 | Speed up navigation by prefetching data for links when they become visible.
17 |
18 |
19 | Load non-essential data after the initial page load to improve performance.
20 |
21 |
22 | Seamlessly load more data as the user scrolls down the page.
23 |
24 |
25 | Load data only when it becomes visible in the viewport.
26 |
27 |
28 | Clear page data from browser history state when logging out of an application.
29 |
30 |
31 |
32 |
33 | ## Upgrade Dependencies
34 |
35 | To upgrade to the Inertia.js v2.0, first use npm to install the client-side adapter of your choice:
36 |
37 |
38 |
39 | ```bash Vue icon="vuejs"
40 | npm install @inertiajs/vue3@^2.0
41 | ```
42 |
43 | ```bash React icon="react"
44 | npm install @inertiajs/react@^2.0
45 | ```
46 |
47 | ```bash Svelte icon="s"
48 | npm install @inertiajs/svelte@^2.0
49 | ```
50 |
51 |
52 |
53 | Next, upgrade the `inertiajs/inertia-laravel` package to use the `2.x` dev branch:
54 |
55 | ```bash
56 | composer require inertiajs/inertia-laravel:^2.0
57 | ```
58 |
59 | ## Breaking Changes
60 |
61 | While a significant release, Inertia.js v2.0 doesn't introduce many breaking changes. Here's a list of all the breaking changes:
62 |
63 | ### Dropped Laravel 8 and 9 Support
64 |
65 | The Laravel adapter now requires Laravel 10 and PHP 8.1 at a minimum.
66 |
67 | ### Dropped Vue 2 Support
68 |
69 | The Vue 2 adapter has been removed. Vue 2 reached End of Life on December 3, 2023, so this felt like it was time.
70 |
71 | ### Router `replace` Method
72 |
73 | The previously deprecated `router.replace` method has been re-instated, but its functionality has changed. It is now used to make [Client Side](/v2/the-basics/manual-visits#client-side-visits) page visits. To make server-side visits that replace the current history entry in the browser, use the `replace` option:
74 |
75 | ```javascript
76 | router.get('/users', { search: 'John' }, { replace: true })
77 | ```
78 |
79 | ### Svelte Adapter
80 |
81 | - Dropped support for Svelte 3 as it reached End of Life on June 20, 2023.
82 | - The `remember` helper has been rename to `useRemember` to be consistent with other helpers.
83 | - Updated `setup` callback in `app.js`. You need to pass `props` when initializing the `App` component. [See setup in app.js](/v2/installation/client-side-setup#initialize-the-inertia-app)
84 | - `setup` callback is now required in `ssr.js`. [See setup in ssr.js](/v2/advanced/server-side-rendering#add-server-entry-point)
85 |
86 | ### Partial Reloads Are Now Async
87 |
88 | Previously partial reloads in Inertia were synchronous, just like all Inertia requests. In v2.0, partial reloads are now asynchronous. Generally this is desirable, but if you were relying on these requests being synchronous, you may need to adjust your code.
89 |
--------------------------------------------------------------------------------
/v2/the-basics/routing.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Routing
3 | ---
4 |
5 | ## Defining Routes
6 |
7 | 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](/v2/the-basics/responses) from those routes.
8 |
9 | ## Shorthand Routes
10 |
11 | If you have a [page](/v2/the-basics/pages) 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.
12 |
13 | ```php
14 | Route::inertia('/about', 'About');
15 | ```
16 |
17 | ## Generating URLs
18 |
19 | 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.
20 |
21 | 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.
22 |
23 | ```php
24 | class UsersController extends Controller
25 | {
26 | public function index()
27 | {
28 | return Inertia::render('Users/Index', [
29 | 'users' => User::all()->map(fn ($user) => [
30 | 'id' => $user->id,
31 | 'name' => $user->name,
32 | 'email' => $user->email,
33 | 'edit_url' => route('users.edit', $user),
34 | ]),
35 | 'create_url' => route('users.create'),
36 | ]);
37 | }
38 | }
39 | ```
40 |
41 | When using Laravel, you have several options to make your server-side routes available to your client-side code:
42 |
43 | ### Wayfinder
44 |
45 | When using [Wayfinder](https://github.com/laravel/wayfinder), you can pass the generated TypeScript method directly to the [Link component](/v2/the-basics/links#wayfinder), [form helpers](/v2/the-basics/forms#wayfinder), or [router methods](/v2/the-basics/manual-visits#wayfinder) and Inertia understand how to handle it. In fact, if you are developing an application using one of Laravel's [starter kits](https://laravel.com/docs/starter-kits), Wayfinder is already configured for you.
46 |
47 | ### Ziggy
48 |
49 | The [Ziggy](https://github.com/tighten/ziggy) library can make your named, server-side routes available to you via a global `route()` function. If you're using the Vue plugin included with Ziggy, you may use the `route()` function directly in your templates.
50 |
51 | ```vue
52 | Create User
53 | ```
54 |
55 | When [server-side rendering](/v2/advanced/server-side-rendering) is enabled, you may pass an options object to the Ziggy plugin in your `ssr.js` file. This should include the route definitions and current location.
56 |
57 | ```js
58 | .use(ZiggyVue, {
59 | ...page.props.ziggy,
60 | location: new URL(page.props.ziggy.location),
61 | });
62 | ```
63 |
64 | ## Customizing the Page URL
65 |
66 | The [page object](/v2/core-concepts/the-protocol#the-page-object) includes a `url` that represents the current page's URL. By default, the Laravel adapter resolves this using the `fullUrl()` method on the `Request` instance, but strips the scheme and host so the result is a relative URL.
67 |
68 | If you need to customize how the URL is resolved, you may provide a resolver within the `urlResolver`method of the Inertia `HandleInertiaRequests` middleware.
69 |
70 | ```php
71 | class HandleInertiaRequests extends Middleware
72 | {
73 | public function urlResolver()
74 | {
75 | return function (Request $request) {
76 | // Return the URL for the request...
77 | };
78 | }
79 | }
80 | ```
81 |
82 | Alternatively, you may define the resolver using the `Inertia::resolveUrlUsing()` method.
83 |
84 | ```php
85 | Inertia::resolveUrlUsing(function (Request $request) {
86 | // Return the URL for the request...
87 | });
88 | ```
89 |
--------------------------------------------------------------------------------
/v2/data-props/polling.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Polling
3 | ---
4 |
5 | ## Poll Helper
6 |
7 | Polling your server for new information on the current page is common, so Inertia provides a poll helper designed to help reduce the amount of boilerplate code. In addition, the poll helper will automatically stop polling when the page is unmounted.
8 |
9 | The only required argument is the polling interval in milliseconds.
10 |
11 |
12 |
13 | ```js Vue icon="vuejs"
14 | import { usePoll } from '@inertiajs/vue3'
15 |
16 | usePoll(2000)
17 | ```
18 |
19 | ```jsx React icon="react"
20 | import { usePoll } from '@inertiajs/react'
21 |
22 | usePoll(2000)
23 | ```
24 |
25 | ```js Svelte icon="s"
26 | import { usePoll } from '@inertiajs/svelte'
27 |
28 | usePoll(2000)
29 | ```
30 |
31 |
32 |
33 | If you need to pass additional request options to the poll helper, you can pass any of the `router.reload` options as the second parameter.
34 |
35 |
36 |
37 | ```js Vue icon="vuejs"
38 | import { usePoll } from '@inertiajs/vue3'
39 |
40 | usePoll(2000, {
41 | onStart() {
42 | console.log('Polling request started')
43 | },
44 | onFinish() {
45 | console.log('Polling request finished')
46 | }
47 | })
48 | ```
49 |
50 | ```jsx React icon="react"
51 | import { usePoll } from '@inertiajs/react'
52 |
53 | usePoll(2000, {
54 | onStart() {
55 | console.log('Polling request started')
56 | },
57 | onFinish() {
58 | console.log('Polling request finished')
59 | }
60 | })
61 | ```
62 |
63 | ```js Svelte icon="s"
64 | import { usePoll } from '@inertiajs/svelte'
65 |
66 | usePoll(2000, {
67 | onStart() {
68 | console.log('Polling request started')
69 | },
70 | onFinish() {
71 | console.log('Polling request finished')
72 | }
73 | })
74 | ```
75 |
76 |
77 |
78 | If you'd like more control over the polling behavior, the poll helper provides `stop` and `start` methods that allow you to manually start and stop polling. You can pass the `autoStart: false` option to the poll helper to prevent it from automatically starting polling when the component is mounted.
79 |
80 |
81 |
82 | ```vue Vue icon="vuejs"
83 |
90 |
91 |
92 |
93 |
94 |
95 | ```
96 |
97 | ```jsx React icon="react"
98 | import { usePoll } from '@inertiajs/react'
99 |
100 | export default () => {
101 | const { start, stop } = usePoll(2000, {}, {
102 | autoStart: false,
103 | })
104 |
105 | return (
106 |
107 |
108 |
109 |
110 | )
111 | }
112 | ```
113 |
114 | ```js Svelte icon="s"
115 | import { usePoll } from '@inertiajs/svelte'
116 |
117 | const { start, stop } = usePoll(2000, {}, {
118 | autoStart: false,
119 | })
120 | ```
121 |
122 |
123 |
124 | ## Throttling
125 |
126 | By default, the poll helper will throttle requests by 90% when the browser tab is in the background. If you'd like to disable this behavior, you can pass the `keepAlive` option to the poll helper.
127 |
128 |
129 |
130 | ```js Vue icon="vuejs"
131 | import { usePoll } from '@inertiajs/vue3'
132 |
133 | usePoll(2000, {}, {
134 | keepAlive: true,
135 | })
136 | ```
137 |
138 | ```jsx React icon="react"
139 | import { usePoll } from '@inertiajs/react'
140 |
141 | usePoll(2000, {}, {
142 | keepAlive: true,
143 | })
144 | ```
145 |
146 | ```js Svelte icon="s"
147 | import { usePoll } from '@inertiajs/svelte'
148 |
149 | usePoll(2000, {}, {
150 | keepAlive: true,
151 | })
152 | ```
153 |
154 |
155 |
--------------------------------------------------------------------------------
/v2/advanced/scroll-management.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Scroll Management
3 | ---
4 |
5 | ## Scroll Resetting
6 |
7 | When navigating between pages, Inertia mimics default browser behavior by automatically resetting the scroll position of the document body (as well as any [scroll regions](#scroll-regions) you've defined) back to the top.
8 |
9 | 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.
10 |
11 | ## Scroll Preservation
12 |
13 | Sometimes it's desirable to prevent the default scroll resetting when making visits. You can disable this behavior by setting the `preserveScroll` option to `true`.
14 |
15 |
16 |
17 | ```js Vue icon="vuejs"
18 | import { router } from '@inertiajs/vue3'
19 |
20 | router.visit(url, { preserveScroll: true })
21 | ```
22 |
23 | ```js React icon="react"
24 | import { router } from '@inertiajs/react'
25 |
26 | router.visit(url, { preserveScroll: true })
27 | ```
28 |
29 | ```js Svelte icon="s"
30 | import { router } from '@inertiajs/svelte'
31 |
32 | router.visit(url, { preserveScroll: true })
33 | ```
34 |
35 |
36 |
37 | If you'd like to only preserve the scroll position if the response includes validation errors, set the `preserveScroll` option to "errors".
38 |
39 |
40 |
41 | ```js Vue icon="vuejs"
42 | import { router } from '@inertiajs/vue3'
43 |
44 | router.visit(url, { preserveScroll: 'errors' })
45 | ```
46 |
47 | ```js React icon="react"
48 | import { router } from '@inertiajs/react'
49 |
50 | router.visit(url, { preserveScroll: 'errors' })
51 | ```
52 |
53 | ```js Svelte icon="s"
54 | import { router } from '@inertiajs/svelte'
55 |
56 | router.visit(url, { preserveScroll: 'errors' })
57 | ```
58 |
59 |
60 |
61 | You can also lazily evaluate the `preserveScroll` option based on the response by providing a callback.
62 |
63 |
64 |
65 | ```js Vue icon="vuejs"
66 | import { router } from '@inertiajs/vue3'
67 |
68 | router.post('/users', data, {
69 | preserveScroll: (page) => page.props.someProp === 'value',
70 | })
71 | ```
72 |
73 | ```js React icon="react"
74 | import { router } from '@inertiajs/react'
75 |
76 | router.post('/users', data, {
77 | preserveScroll: (page) => page.props.someProp === 'value',
78 | })
79 | ```
80 |
81 | ```js Svelte icon="s"
82 | import { router } from '@inertiajs/svelte'
83 |
84 | router.post('/users', data, {
85 | preserveScroll: (page) => page.props.someProp === 'value',
86 | })
87 | ```
88 |
89 |
90 |
91 | When using an [Inertia link](/v2/the-basics/links), you can preserve the scroll position using the `preserveScroll` prop.
92 |
93 |
94 |
95 | ```vue Vue icon="vuejs"
96 | import { Link } from '@inertiajs/vue3'
97 |
98 | Home
99 | ```
100 |
101 | ```jsx React icon="react"
102 | import { Link } from '@inertiajs/react'
103 |
104 | Home
105 | ```
106 |
107 | ```svelte Svelte icon="s"
108 | import { inertia, Link } from '@inertiajs/svelte'
109 |
110 | Home
111 |
112 | Home
113 | ```
114 |
115 |
116 |
117 | ## Scroll Regions
118 |
119 | If your app doesn't use document body scrolling, but instead has scrollable elements (using the `overflow` CSS property), scroll resetting will not work.
120 |
121 | In these situations, you must tell Inertia which scrollable elements to manage by adding the `scroll-region` attribute to the element.
122 |
123 | ```html
124 |
125 |
126 |
127 | ```
128 |
129 | ## Text Fragments
130 |
131 | [Text fragments](https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment/Text_fragments) allow you to link directly to specific text on a page using a special URL syntax like `#:~:text=term`. However, the browser removes the fragment directive before any JavaScript runs, so text fragments only work if the targeted text is present in the initial HTML response.
132 |
133 | To use text fragments with your Inertia pages, enable [server-side rendering](/v2/advanced/server-side-rendering).
134 |
--------------------------------------------------------------------------------
/v2/security/csrf-protection.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSRF Protection
3 | ---
4 |
5 | ## Making Requests
6 |
7 | 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.
8 |
9 | If your server-side framework includes cross-site request forgery (CSRF) protection, you'll need to ensure that each Inertia request includes the necessary CSRF token for `POST`, `PUT`, `PATCH`, and `DELETE` requests.
10 |
11 | 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.**
12 |
13 | 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.
14 |
15 |
16 |
17 | ```js Vue icon="vuejs"
18 | import { router, usePage } from '@inertiajs/vue3'
19 |
20 | const page = usePage()
21 |
22 | router.post('/users', {
23 | _token: page.props.csrf_token,
24 | name: 'John Doe',
25 | email: 'john.doe@example.com',
26 | })
27 | ```
28 |
29 | ```js React icon="react"
30 | import { router, usePage } from '@inertiajs/react'
31 |
32 | const props = usePage().props
33 |
34 | router.post('/users', {
35 | _token: props.csrf_token,
36 | name: 'John Doe',
37 | email: 'john.doe@example.com',
38 | })
39 | ```
40 |
41 | ```js Svelte icon="s"
42 | import { page, router } from '@inertiajs/svelte'
43 |
44 | router.post('/users', {
45 | _token: $page.props.csrf_token,
46 | name: 'John Doe',
47 | email: 'john.doe@example.com',
48 | })
49 | ```
50 |
51 |
52 |
53 | You can even use Inertia's [shared data](/v2/data-props/shared-data) functionality to automatically include the `csrf_token` with each response.
54 |
55 | However, a better approach is to use the CSRF functionality already built into [axios](https://github.com/axios/axios) for this. Axios is the HTTP library that Inertia uses under the hood.
56 |
57 | 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.
58 |
59 | 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.
60 |
61 | ## Handling Mismatches
62 |
63 | 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.
64 |
65 |
66 |
67 | 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](/shared-data#flash-messages) with Inertia for this to work.
68 |
69 | 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.
70 |
71 | ```php
72 | use Symfony\Component\HttpFoundation\Response;
73 |
74 | ->withExceptions(function (Exceptions $exceptions) {
75 | $exceptions->respond(function (Response $response) {
76 | if ($response->getStatusCode() === 419) {
77 | return back()->with([
78 | 'message' => 'The page expired, please try again.',
79 | ]);
80 | }
81 |
82 | return $response;
83 | });
84 | });
85 | ```
86 |
87 | 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.
88 |
89 |
90 |
--------------------------------------------------------------------------------
/v1/advanced/scroll-management.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Scroll Management
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | ## Scroll Resetting
8 |
9 | When navigating between pages, Inertia mimics default browser behavior by automatically resetting the scroll position of the document body (as well as any [scroll regions](#scroll-regions) you've defined) back to the top.
10 |
11 | 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.
12 |
13 | ## Scroll Preservation
14 |
15 | Sometimes it's desirable to prevent the default scroll resetting when making visits. You can disable this behavior by setting the `preserveScroll` option to `false`.
16 |
17 |
18 |
19 | ```js Vue 2 icon="vuejs"
20 | import { router } from '@inertiajs/vue2'
21 |
22 | router.visit(url, { preserveScroll: false })
23 | ```
24 |
25 | ```js Vue 3 icon="vuejs"
26 | import { router } from '@inertiajs/vue3'
27 |
28 | router.visit(url, { preserveScroll: false })
29 | ```
30 |
31 | ```js React icon="react"
32 | import { router } from '@inertiajs/react'
33 |
34 | router.visit(url, { preserveScroll: false })
35 | ```
36 |
37 | ```js Svelte icon="s"
38 | import { router } from '@inertiajs/svelte'
39 |
40 | router.visit(url, { preserveScroll: false })
41 | ```
42 |
43 |
44 |
45 | If you'd like to only preserve the scroll position if the response includes validation errors, set the `preserveScroll` option to "errors".
46 |
47 |
48 |
49 | ```js Vue 2 icon="vuejs"
50 | import { router } from '@inertiajs/vue2'
51 |
52 | router.visit(url, { preserveScroll: 'errors' })
53 | ```
54 |
55 | ```js Vue 3 icon="vuejs"
56 | import { router } from '@inertiajs/vue3'
57 |
58 | router.visit(url, { preserveScroll: 'errors' })
59 | ```
60 |
61 | ```js React icon="react"
62 | import { router } from '@inertiajs/react'
63 |
64 | router.visit(url, { preserveScroll: 'errors' })
65 | ```
66 |
67 | ```js Svelte icon="s"
68 | import { router } from '@inertiajs/svelte'
69 |
70 | router.visit(url, { preserveScroll: 'errors' })
71 | ```
72 |
73 |
74 |
75 | You can also lazily evaluate the `preserveScroll` option based on the response by providing a callback.
76 |
77 |
78 |
79 | ```js Vue 2 icon="vuejs"
80 | import { router } from '@inertiajs/vue2'
81 |
82 | router.post('/users', data, {
83 | preserveScroll: (page) => page.props.someProp === 'value',
84 | })
85 | ```
86 |
87 | ```js Vue 3 icon="vuejs"
88 | import { router } from '@inertiajs/vue3'
89 |
90 | router.post('/users', data, {
91 | preserveScroll: (page) => page.props.someProp === 'value',
92 | })
93 | ```
94 |
95 | ```js React icon="react"
96 | import { router } from '@inertiajs/react'
97 |
98 | router.post('/users', data, {
99 | preserveScroll: (page) => page.props.someProp === 'value',
100 | })
101 | ```
102 |
103 | ```js Svelte icon="s"
104 | import { router } from '@inertiajs/svelte'
105 |
106 | router.post('/users', data, {
107 | preserveScroll: (page) => page.props.someProp === 'value',
108 | })
109 | ```
110 |
111 |
112 |
113 | When using an [Inertia link](/v1/the-basics/links), you can preserve the scroll position using the `preserveScroll` prop.
114 |
115 |
116 |
117 | ```vue Vue 2 icon="vuejs"
118 | import { Link } from '@inertiajs/vue2'
119 |
120 | Home
121 | ```
122 |
123 | ```vue Vue 3 icon="vuejs"
124 | import { Link } from '@inertiajs/vue3'
125 |
126 | Home
127 | ```
128 |
129 | ```jsx React icon="react"
130 | import { Link } from '@inertiajs/react'
131 |
132 | Home
133 | ```
134 |
135 | ```svelte Svelte icon="s"
136 | import { inertia, Link } from '@inertiajs/svelte'
137 |
138 | Home
139 |
140 | Home
141 | ```
142 |
143 |
144 |
145 | ## Scroll Regions
146 |
147 | If your app doesn't use document body scrolling, but instead has scrollable elements (using the `overflow` CSS property), scroll resetting will not work.
148 |
149 | In these situations, you must tell Inertia which scrollable elements to manage by adding the `scroll-region` attribute to the element.
150 |
151 | ```html
152 |
153 |
154 |
155 | ```
156 |
--------------------------------------------------------------------------------
/v1/advanced/csrf-protection.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSRF Protection
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | ## Making Requests
8 |
9 | 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.
10 |
11 | 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.
12 |
13 | 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.**
14 |
15 | 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.
16 |
17 |
18 |
19 | ```js Vue 2 icon="vuejs"
20 | import { router } from '@inertiajs/vue2'
21 |
22 | router.post('/users', {
23 | _token: this.$page.props.csrf_token,
24 | name: 'John Doe',
25 | email: 'john.doe@example.com',
26 | })
27 | ```
28 |
29 | ```js Vue 3 icon="vuejs"
30 | import { router, usePage } from '@inertiajs/vue3'
31 |
32 | const page = usePage()
33 |
34 | router.post('/users', {
35 | _token: page.props.csrf_token,
36 | name: 'John Doe',
37 | email: 'john.doe@example.com',
38 | })
39 | ```
40 |
41 | ```js React icon="react"
42 | import { router, usePage } from '@inertiajs/react'
43 |
44 | const props = usePage().props
45 |
46 | router.post('/users', {
47 | _token: props.csrf_token,
48 | name: 'John Doe',
49 | email: 'john.doe@example.com',
50 | })
51 | ```
52 |
53 | ```js Svelte icon="s"
54 | import { page, router } from '@inertiajs/svelte'
55 |
56 | router.post('/users', {
57 | _token: $page.props.csrf_token,
58 | name: 'John Doe',
59 | email: 'john.doe@example.com',
60 | })
61 | ```
62 |
63 |
64 |
65 | You can even use Inertia's [shared data](/v1/the-basics/shared-data) functionality to automatically include the `csrf_token` with each response.
66 |
67 | However, a better approach is to use the CSRF functionality already built into [axios](https://github.com/axios/axios) for this. Axios is the HTTP library that Inertia uses under the hood.
68 |
69 | 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.
70 |
71 | 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.
72 |
73 | ## Handling Mismatches
74 |
75 | 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.
76 |
77 |
78 |
79 | 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](/shared-data#flash-messages) with Inertia for this to work.
80 |
81 | 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.
82 |
83 | ```php
84 | use Symfony\Component\HttpFoundation\Response;
85 |
86 | ->withExceptions(function (Exceptions $exceptions) {
87 | $exceptions->respond(function (Response $response) {
88 | if ($response->getStatusCode() === 419) {
89 | return back()->with([
90 | 'message' => 'The page expired, please try again.',
91 | ]);
92 | }
93 |
94 | return $response;
95 | });
96 | });
97 | ```
98 |
99 | 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.
100 |
101 |
102 |
--------------------------------------------------------------------------------
/v2/data-props/shared-data.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Shared Data
3 | ---
4 |
5 | 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.
6 |
7 | ## Sharing Data
8 |
9 | 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.
10 |
11 | In Laravel applications, this is typically handled by the `HandleInertiaRequests` middleware that is automatically installed when installing the [server-side adapter](/v2/installation/server-side-setup#middleware).
12 |
13 | ```php
14 | class HandleInertiaRequests extends Middleware
15 | {
16 | public function share(Request $request)
17 | {
18 | return array_merge(parent::share($request), [
19 | // Synchronously...
20 | 'appName' => config('app.name'),
21 |
22 | // Lazily...
23 | 'auth.user' => fn () => $request->user()
24 | ? $request->user()->only('id', 'name', 'email')
25 | : null,
26 | ]);
27 | }
28 | }
29 | ```
30 |
31 | Alternatively, you can manually share data using the `Inertia::share` method.
32 |
33 | ```php
34 | use Inertia\Inertia;
35 |
36 | // Synchronously...
37 | Inertia::share('appName', config('app.name'));
38 |
39 | // Lazily...
40 | Inertia::share('user', fn (Request $request) => $request->user()
41 | ? $request->user()->only('id', 'name', 'email')
42 | : null
43 | );
44 | ```
45 |
46 | Shared data should be used sparingly as all shared data is included with every response.
47 |
48 | Page props and shared data are merged together, so be sure to namespace your shared data appropriately to avoid collisions.
49 |
50 | ## Sharing Once Props
51 |
52 | You may share data that is resolved only once and remembered by the client across subsequent navigations using [once props](/v2/data-props/once-props).
53 |
54 | ```php
55 | class HandleInertiaRequests extends Middleware
56 | {
57 | public function share(Request $request)
58 | {
59 | return array_merge(parent::share($request), [
60 | 'countries' => Inertia::once(fn () => Country::all()),
61 | ]);
62 | }
63 | }
64 | ```
65 |
66 | Alternatively, you may define a dedicated `shareOnce()` method in the middleware. The middleware will evaluate both `share()` and `shareOnce()`, merging the results.
67 |
68 | ```php
69 | class HandleInertiaRequests extends Middleware
70 | {
71 | public function shareOnce(Request $request): array
72 | {
73 | return array_merge(parent::shareOnce($request), [
74 | 'countries' => fn () => Country::all(),
75 | ]);
76 | }
77 | }
78 | ```
79 |
80 | You may also share once props manually using the `Inertia::shareOnce()` method.
81 |
82 | ```php
83 | Inertia::shareOnce('countries', fn () => Country::all());
84 | ```
85 |
86 | ## Accessing Shared Data
87 |
88 | 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.
89 |
90 |
91 |
92 | ```vue Vue icon="vuejs"
93 |
101 |
102 |
103 |
104 |
105 | You are logged in as: {{ user.name }}
106 |
107 |
108 |
109 |
110 |
111 |
112 | ```
113 |
114 | ```jsx React icon="react"
115 | import { usePage } from '@inertiajs/react'
116 |
117 | export default function Layout({ children }) {
118 | const { auth } = usePage().props
119 |
120 | return (
121 |
122 |
123 | You are logged in as: {auth.user.name}
124 |
125 |
126 | {children}
127 |
128 |
129 | )
130 | }
131 | ```
132 |
133 | ```svelte Svelte icon="s"
134 |
137 |
138 |
139 |
140 | You are logged in as: {$page.props.auth.user.name}
141 |
142 |
143 |
144 |
145 |
146 | ```
147 |
148 |
149 |
150 | ## Flash Data
151 |
152 | For one-time notifications like toast messages or success alerts, you may use [flash data](/v2/data-props/flash-data). Unlike shared data, flash data is not persisted in the browser's history state, so it won't reappear when navigating through history.
153 |
--------------------------------------------------------------------------------
/v2/installation/server-side-setup.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Server-Side Setup
3 | ---
4 |
5 | The first step when installing Inertia is to configure your server-side framework. Inertia maintains an official server-side adapter for [Laravel](https://laravel.com/). For other frameworks, please see the [community adapters](/v2/installation/community-adapters).
6 |
7 | 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.
8 |
9 |
16 | Laravel's starter kits provide out-of-the-box scaffolding for new Inertia applications.
17 |
18 | 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.
19 |
20 |
21 | ## Installation
22 |
23 |
24 |
25 | First, install the Inertia server-side adapter using the Composer package manager.
26 |
27 | ```bash
28 | composer require inertiajs/inertia-laravel
29 | ```
30 |
31 |
32 |
33 | Next, setup the root template that will be loaded on the first page visit to your application. This template should include your site's CSS and JavaScript assets, along with the `@inertia` and `@inertiaHead` directives.
34 |
35 | ```blade
36 |
37 |
38 |
39 |
40 | @vite('resources/js/app.js')
41 | @inertiaHead
42 |
43 |
44 | @inertia
45 |
46 |
47 | ```
48 |
49 | For React applications, it's recommended to include the `@viteReactRefresh` directive before the `@vite` directive to enable Fast Refresh in development.
50 |
51 | The `@inertia` directive renders a `
` element with an `id` of `app`. This element serves as the mounting point for your JavaScript application. You may customize the `id` by passing a different value to the directive.
52 |
53 | ```blade
54 |
55 | ...
56 |
57 | @inertia('custom-app-id')
58 |
59 |
60 | ```
61 |
62 | If you change the `id` of the root element, be sure to update it [client-side](/v2/installation/client-side-setup#defining-a-root-element) as well.
63 |
64 | 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.
65 |
66 |
67 |
68 | 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.
69 |
70 | ```sh
71 | php artisan inertia:middleware
72 | ```
73 |
74 | Once the middleware has been published, append the `HandleInertiaRequests` middleware to the `web` middleware group in your application's `bootstrap/app.php` file.
75 |
76 | ```php
77 | use App\Http\Middleware\HandleInertiaRequests;
78 |
79 | ->withMiddleware(function (Middleware $middleware) {
80 | $middleware->web(append: [
81 | HandleInertiaRequests::class,
82 | ]);
83 | })
84 | ```
85 |
86 | This middleware provides a `version()` method for setting your [asset version](/v2/advanced/asset-versioning), as well as a `share()` method for defining [shared data](/v2/data-props/shared-data).
87 |
88 |
89 |
90 | That's it, you're all ready to go server-side! Now you're ready to start creating Inertia [pages](/v2/the-basics/pages) and rendering them via [responses](/v2/the-basics/responses).
91 |
92 | ```php
93 | use Inertia\Inertia;
94 |
95 | class EventsController extends Controller
96 | {
97 | public function show(Event $event)
98 | {
99 | return Inertia::render('Event/Show', [
100 | 'event' => $event->only(
101 | 'id',
102 | 'title',
103 | 'start_date',
104 | 'description',
105 | ),
106 | ]);
107 | }
108 | }
109 | ```
110 |
111 |
112 |
--------------------------------------------------------------------------------
/v2/data-props/once-props.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Once Props
3 | ---
4 |
5 | Some data rarely changes, is expensive to compute, or is simply large. Rather than including this data in every response, you may use _once props_. These props are remembered by the client and reused on subsequent pages that include the same prop. This makes them ideal for [shared data](/v2/data-props/shared-data).
6 |
7 | ## Creating Once Props
8 |
9 | To create a once prop, use the `Inertia::once()` method when returning your response. This method receives a callback that returns the prop data.
10 |
11 | ```php
12 | return Inertia::render('Billing', [
13 | 'plans' => Inertia::once(fn () => Plan::all()),
14 | ]);
15 | ```
16 |
17 | After the client has received this prop, subsequent requests will skip resolving the callback and exclude the prop from the response. The client only remembers once props while navigating between pages that include them.
18 |
19 | Navigating to a page without the once prop will forget the remembered value, and it will be resolved again on the next page that has it. In practice, this is rarely an issue since once props are typically used as shared data or within a specific section of your application.
20 |
21 | ## Forcing a Refresh
22 |
23 | You may force a once prop to be refreshed using the `fresh()` method.
24 |
25 | ```php
26 | return Inertia::render('Billing', [
27 | 'plans' => Inertia::once(fn () => Plan::all())->fresh(),
28 | ]);
29 | ```
30 |
31 | This method also accepts a boolean, allowing you to conditionally refresh the prop.
32 |
33 | ```php
34 | return Inertia::render('Billing', [
35 | 'plans' => Inertia::once(fn () => Plan::all())->fresh($condition),
36 | ]);
37 | ```
38 |
39 | ## Refreshing from the Client
40 |
41 | You may refresh a once prop from the client-side using a [partial reload](/v2/data-props/partial-reloads). The server will always resolve a once prop when explicitly requested.
42 |
43 |
44 |
45 | ```js Vue icon="vuejs"
46 | import { router } from '@inertiajs/vue3'
47 |
48 | router.reload({ only: ['plans'] })
49 | ```
50 |
51 | ```js React icon="react"
52 | import { router } from '@inertiajs/react'
53 |
54 | router.reload({ only: ['plans'] })
55 | ```
56 |
57 | ```js Svelte icon="s"
58 | import { router } from '@inertiajs/svelte'
59 |
60 | router.reload({ only: ['plans'] })
61 | ```
62 |
63 |
64 |
65 | ## Expiration
66 |
67 | You may set an expiration time using the `until()` method. This method accepts a `DateTimeInterface`, `DateInterval`, or an integer (seconds). The prop will be refreshed on a subsequent visit after the expiration time has passed.
68 |
69 | ```php
70 | return Inertia::render('Dashboard', [
71 | 'rates' => Inertia::once(fn () => ExchangeRate::all())->until(now()->addDay()),
72 | ]);
73 | ```
74 |
75 | ## Custom Keys
76 |
77 | You may assign a custom key to the prop using the `as()` method. This is useful when you want to share data across multiple pages while using different prop names.
78 |
79 | ```php
80 | // Team member list...
81 | return Inertia::render('Team/Index', [
82 | 'memberRoles' => Inertia::once(fn () => Role::all())->as('roles'),
83 | ]);
84 |
85 | // Invite form...
86 | return Inertia::render('Team/Invite', [
87 | 'availableRoles' => Inertia::once(fn () => Role::all())->as('roles'),
88 | ]);
89 | ```
90 |
91 | Both pages share the same underlying data because they use the same custom key, so the prop is only resolved for whichever page you visit first.
92 |
93 | ## Sharing Once Props
94 |
95 | You may share once props globally using the `Inertia::share()` method.
96 |
97 | ```php
98 | Inertia::share('countries', Inertia::once(fn () => Country::all()));
99 | ```
100 |
101 | Or, for convenience, you may use the `shareOnce()` method.
102 |
103 | ```php
104 | Inertia::shareOnce('countries', fn () => Country::all());
105 | ```
106 |
107 | You may also chain `as()`, `fresh()`, and `until()` onto the `shareOnce` method.
108 |
109 | ```php
110 | Inertia::shareOnce('countries', fn () => Country::all())->until(now()->addDay());
111 | ```
112 |
113 | Additionally, you may define a dedicated `shareOnce()` method in your middleware. The middleware will evaluate both `share()` and `shareOnce()`, merging the results.
114 |
115 | ```php
116 | class HandleInertiaRequests extends Middleware
117 | {
118 | public function shareOnce(Request $request): array
119 | {
120 | return array_merge(parent::shareOnce($request), [
121 | 'countries' => fn () => Country::all(),
122 | ]);
123 | }
124 | }
125 | ```
126 |
127 | ## Prefetching
128 |
129 | Once props are compatible with [prefetching](/v2/data-props/prefetching). The client automatically includes any remembered once props in prefetched responses, so navigating to a prefetched page will already have the once props available.
130 |
131 | Prefetched pages containing an expired once prop will be invalidated from the cache.
132 |
133 | ## Combining with Other Prop Types
134 |
135 | The `once()` modifier may be chained onto [deferred](/v2/data-props/deferred-props), [merge](/v2/data-props/merging-props), and [optional](/v2/data-props/partial-reloads#lazy-data-evaluation) props.
136 |
137 | ```php
138 | return Inertia::render('Dashboard', [
139 | 'permissions' => Inertia::defer(fn () => Permission::all())->once(),
140 | 'activity' => Inertia::merge(fn () => $user->recentActivity())->once(),
141 | 'categories' => Inertia::optional(fn () => Category::all())->once(),
142 | ]);
143 | ```
144 |
--------------------------------------------------------------------------------
/snippets/color-generator.jsx:
--------------------------------------------------------------------------------
1 | export const ColorGenerator = () => {
2 | const [hue, setHue] = useState(180);
3 | const [saturation, setSaturation] = useState(50);
4 | const [lightness, setLightness] = useState(50);
5 | const [colors, setColors] = useState([]);
6 |
7 | useEffect(() => {
8 | const newColors = [];
9 | for (let i = 0; i < 5; i++) {
10 | const l = Math.max(10, Math.min(90, lightness - 20 + i * 10));
11 | newColors.push(`hsl(${hue}, ${saturation}%, ${l}%)`);
12 | }
13 | setColors(newColors);
14 | }, [hue, saturation, lightness]);
15 |
16 | const copyToClipboard = (color) => {
17 | navigator.clipboard
18 | .writeText(color)
19 | .then(() => {
20 | console.log(`Copied ${color} to clipboard!`);
21 | })
22 | .catch((err) => {
23 | console.error("Failed to copy: ", err);
24 | });
25 | };
26 |
27 | return (
28 |
29 |
30 |
31 |
54 |
55 |
74 |
75 |
94 |
95 |
96 |
97 | {colors.map((color, idx) => (
98 |
copyToClipboard(color)}
104 | />
105 | ))}
106 |
107 |
108 |
109 |
110 | Base color: hsl({hue}, {saturation}%, {lightness}%)
111 |
112 |
113 |
114 |
115 | );
116 | };
117 |
--------------------------------------------------------------------------------
/v1/installation/client-side-setup.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Client-side Setup
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | Once you have your [server-side framework configured](/v1/installation/server-side-setup), you then need to setup your client-side framework. Inertia currently provides support for React, Vue, and Svelte.
8 |
9 | ## Laravel Starter Kits
10 |
11 | Laravel's [starter kits](https://laravel.com/docs/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.
12 |
13 | ## Install Dependencies
14 |
15 | First, install the Inertia client-side adapter corresponding to your framework of choice.
16 |
17 |
18 |
19 | ```bash Vue 2
20 | npm install @inertiajs/vue2
21 | ```
22 |
23 | ```bash Vue 3
24 | npm install @inertiajs/vue3
25 | ```
26 |
27 | ```bash React icon="react"
28 | npm install @inertiajs/react
29 | ```
30 |
31 | ```bash Svelte icon="s"
32 | npm install @inertiajs/svelte
33 | ```
34 |
35 |
36 |
37 | ## Initialize the Inertia App
38 |
39 | 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.
40 |
41 |
42 |
43 | ```js Vue 2 icon="vuejs"
44 | import Vue from 'vue'
45 | import { createInertiaApp } from '@inertiajs/vue2'
46 |
47 | createInertiaApp({
48 | resolve: name => {
49 | const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
50 | return pages[`./Pages/${name}.vue`]
51 | },
52 | setup({ el, App, props, plugin }) {
53 | Vue.use(plugin)
54 |
55 | new Vue({
56 | render: h => h(App, props),
57 | }).$mount(el)
58 | },
59 | })
60 | ```
61 |
62 | ```js Vue 3 icon="vuejs"
63 | import { createApp, h } from 'vue'
64 | import { createInertiaApp } from '@inertiajs/vue3'
65 |
66 | createInertiaApp({
67 | resolve: name => {
68 | const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
69 | return pages[`./Pages/${name}.vue`]
70 | },
71 | setup({ el, App, props, plugin }) {
72 | createApp({ render: () => h(App, props) })
73 | .use(plugin)
74 | .mount(el)
75 | },
76 | })
77 | ```
78 |
79 | ```jsx React icon="react"
80 | import { createInertiaApp } from '@inertiajs/react'
81 | import { createRoot } from 'react-dom/client'
82 |
83 | createInertiaApp({
84 | resolve: name => {
85 | const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
86 | return pages[`./Pages/${name}.jsx`]
87 | },
88 | setup({ el, App, props }) {
89 | createRoot(el).render()
90 | },
91 | })
92 | ```
93 |
94 | ```js Svelte icon="s"
95 | import { createInertiaApp } from '@inertiajs/svelte'
96 |
97 | createInertiaApp({
98 | resolve: name => {
99 | const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
100 | return pages[`./Pages/${name}.svelte`]
101 | },
102 | setup({ el, App, props }) {
103 | new App({ target: el, props })
104 | },
105 | })
106 | ```
107 |
108 |
109 |
110 | The `setup` callback receives everything necessary to initialize the client-side framework, including the root Inertia `App` component.
111 |
112 | ## Resolving Components
113 |
114 | 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.
115 |
116 |
117 |
118 | ```js Vue 2 icon="vuejs"
119 | // Vite
120 | resolve: name => {
121 | const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
122 | return pages[`./Pages/${name}.vue`]
123 | },
124 |
125 | // Webpack
126 | resolve: name => require(`./Pages/${name}`),
127 | ```
128 |
129 | ```js Vue 3 icon="vuejs"
130 | // Vite
131 | resolve: name => {
132 | const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
133 | return pages[`./Pages/${name}.vue`]
134 | },
135 |
136 | // Webpack
137 | resolve: name => require(`./Pages/${name}`),
138 | ```
139 |
140 | ```js React icon="react"
141 | // Vite
142 | resolve: name => {
143 | const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
144 | return pages[`./Pages/${name}.jsx`]
145 | },
146 |
147 | // Webpack
148 | resolve: name => require(`./Pages/${name}`),
149 | ```
150 |
151 | ```js Svelte icon="s"
152 | // Vite
153 | resolve: name => {
154 | const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
155 | return pages[`./Pages/${name}.svelte`]
156 | },
157 |
158 | // Webpack
159 | resolve: name => require(`./Pages/${name}.svelte`),
160 | ```
161 |
162 |
163 |
164 | 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](/code-splitting) documentation.
165 |
166 | ## Defining a Root Element
167 |
168 | 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.
169 |
170 | ```js
171 | createInertiaApp({
172 | id: 'my-app',
173 | // ...
174 | })
175 | ```
176 |
--------------------------------------------------------------------------------
/v2/data-props/deferred-props.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Deferred Props
3 | ---
4 |
5 | Inertia's deferred props feature allows you to defer the loading of certain page data until after the initial page render. This can be useful for improving the perceived performance of your app by allowing the initial page render to happen as quickly as possible.
6 |
7 | ## Server Side
8 |
9 | To defer a prop, you can use the `Inertia::defer()` method when returning your response. This method receives a callback that returns the prop data. The callback will be executed in a separate request after the initial page render.
10 |
11 | ```php
12 | Route::get('/users', function () {
13 | return Inertia::render('Users/Index', [
14 | 'users' => User::all(),
15 | 'roles' => Role::all(),
16 | 'permissions' => Inertia::defer(fn () => Permission::all()),
17 | ]);
18 | });
19 | ```
20 |
21 | ### Grouping Requests
22 |
23 | By default, all deferred props get fetched in one request after the initial page is rendered, but you can choose to fetch data in parallel by grouping props together.
24 |
25 | ```php
26 | Route::get('/users', function () {
27 | return Inertia::render('Users/Index', [
28 | 'users' => User::all(),
29 | 'roles' => Role::all(),
30 | 'permissions' => Inertia::defer(fn () => Permission::all()),
31 | 'teams' => Inertia::defer(fn () => Team::all(), 'attributes'),
32 | 'projects' => Inertia::defer(fn () => Project::all(), 'attributes'),
33 | 'tasks' => Inertia::defer(fn () => Task::all(), 'attributes'),
34 | ]);
35 | });
36 | ```
37 |
38 | In the example above, the `teams`, `projects`, and `tasks` props will be fetched in one request, while the `permissions` prop will be fetched in a separate request in parallel. Group names are arbitrary strings and can be anything you choose.
39 |
40 | ## Client Side
41 |
42 | On the client side, Inertia provides the `Deferred` component to help you manage deferred props. This component will automatically wait for the specified deferred props to be available before rendering its children.
43 |
44 |
45 |
46 | ```vue Vue icon="vuejs"
47 |
50 |
51 |
52 |
53 |
54 |
171 | {/snippet}
172 |
173 |
174 |
175 | ```
176 |
177 |
178 |
179 | ## Combining with Once Props
180 |
181 | You may chain the `once()` modifier onto a deferred prop to ensure the data is resolved only once and remembered by the client across subsequent navigations.
182 |
183 | ```php
184 | return Inertia::render('Dashboard', [
185 | 'stats' => Inertia::defer(fn () => Stats::generate())->once(),
186 | ]);
187 | ```
188 |
189 | For more information on once props, see the [once props](/v2/data-props/once-props) documentation.
190 |
--------------------------------------------------------------------------------
/v2/data-props/merging-props.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Merging Props
3 | ---
4 |
5 | Inertia overwrites props with the same name when reloading a page. However, you may need to merge new data with existing data instead. For example, when implementing a "load more" button for paginated results. The [Infinite scroll](/v2/data-props/infinite-scroll) component uses prop merging under the hood.
6 |
7 | Prop merging only works during [partial reloads](/v2/data-props/partial-reloads). Full page visits will always replace props entirely, even if you've marked them for merging.
8 |
9 | ## Merge Methods
10 |
11 | To merge a prop instead of overwriting it, you may use the `Inertia::merge()` method when returning your response.
12 |
13 | ```php
14 | Route::get('/items', function () {
15 | // Static array of tags...
16 | $allTags = [
17 | 'Laravel', 'React', 'Vue', 'Tailwind', 'Inertia',
18 | 'PHP', 'JavaScript', 'TypeScript', 'Docker', 'Vite',
19 | ];
20 |
21 | // Get chunk of tags by page...
22 | $page = request()->input('page', 1);
23 | $perPage = 5;
24 | $offset = ($page - 1) * $perPage;
25 | $tags = array_slice($allTags, $offset, $perPage);
26 |
27 | return Inertia::render('Tags/Index', [
28 | 'tags' => Inertia::merge($tags),
29 | ]);
30 | });
31 | ```
32 |
33 | The `Inertia::merge()` method will append new items to existing arrays at the root level. You may change this behavior to prepend items instead.
34 |
35 | ```php
36 | // Append at root level (default)...
37 | Inertia::merge($items);
38 |
39 | // Prepend at root level...
40 | Inertia::merge($items)->prepend();
41 | ```
42 |
43 | For more precise control, you can target specific nested properties for merging while replacing the rest of the object.
44 |
45 | ```php
46 | // Only append to the 'data' array, replace everything else...
47 | Inertia::merge(User::paginate())->append('data');
48 |
49 | // Prepend to the 'messages' array...
50 | Inertia::merge($chatData)->prepend('messages');
51 | ```
52 |
53 | You can combine multiple operations and target several properties at once.
54 |
55 | ```php
56 | Inertia::merge($forumData)
57 | ->append('posts')
58 | ->prepend('announcements');
59 |
60 | // Target multiple properties...
61 | Inertia::merge($dashboardData)
62 | ->append(['notifications', 'activities']);
63 | ```
64 |
65 | On the client side, Inertia handles all the merging automatically according to your server-side configuration.
66 |
67 | ## Matching Items
68 |
69 | When merging arrays, you may use the `matchOn` parameter to match existing items by a specific field and update them instead of appending new ones.
70 |
71 | ```php
72 | // Match posts by ID, update existing ones...
73 | Inertia::merge($postData)->append('data', matchOn: 'id');
74 |
75 | // Multiple properties with different match fields...
76 | Inertia::merge($complexData)->append([
77 | 'users.data' => 'id',
78 | 'messages' => 'uuid',
79 | ]);
80 | ```
81 |
82 | In the first example, Inertia will iterate over the `data` array and attempt to match each item by its `id` field. If a match is found, the existing item will be replaced. If no match is found, the new item will be appended.
83 |
84 | ## Deep Merge
85 |
86 | Instead of specifying which nested paths should be merged, you may use `Inertia::deepMerge()`to ensure a deep merge of the entire structure.
87 |
88 | ```php
89 | Route::get('/chat', function () {
90 | $chatData = [
91 | 'messages' => [
92 | ['id' => 4, 'text' => 'Hello there!', 'user' => 'Alice'],
93 | ['id' => 5, 'text' => 'How are you?', 'user' => 'Bob'],
94 | ],
95 | 'online' => 12,
96 | ];
97 |
98 | return Inertia::render('Chat', [
99 | 'chat' => Inertia::deepMerge($chatData)->matchOn('messages.id'),
100 | ]);
101 | });
102 | ```
103 |
104 | `Inertia::deepMerge()` was introduced before `Inertia::merge()` had support for prepending and targeting nested paths. In most cases, `Inertia::merge()` with its append and prepend methods should be sufficient.
105 |
106 | ## Client Side Visits
107 |
108 | You can also merge props directly on the client side without making a server request using [client side visits](/v2/the-basics/manual-visits#client-side-visits). Inertia provides [prop helper methods](/v2/the-basics/manual-visits#prop-helpers) that allow you to append, prepend, or replace prop values.
109 |
110 | ## Combining with Deferred Props
111 |
112 | You may combine [deferred props](/v2/data-props/deferred-props) with mergeable props to defer the loading of the prop and ultimately mark it as mergeable once it's loaded.
113 |
114 | ```php
115 | Route::get('/users', function () {
116 | $page = request()->input('page', 1);
117 | $perPage = request()->input('per_page', 10);
118 |
119 | return Inertia::render('Users/Index', [
120 | 'results' => Inertia::defer(fn() => User::paginate($perPage, page: $page))->deepMerge(),
121 | ]);
122 | });
123 | ```
124 |
125 | ## Combining with Once Props
126 |
127 | You may chain the `once()` modifier onto a merge prop to ensure the data is resolved only once and remembered by the client across subsequent navigations.
128 |
129 | ```php
130 | return Inertia::render('Users/Index', [
131 | 'activity' => Inertia::merge(fn () => $user->recentActivity())->once(),
132 | ]);
133 | ```
134 |
135 | For more information on once props, see the [once props](/v2/data-props/once-props) documentation.
136 |
137 | ## Resetting Props
138 |
139 | On the client side, you can indicate to the server that you would like to reset the prop. This is useful when you want to clear the prop value before merging new data, such as when the user enters a new search query on a paginated list.
140 |
141 | The `reset` request option accepts an array of the props keys you would like to reset.
142 |
143 | ```js
144 | router.reload({
145 | reset: ['results'],
146 | // ...
147 | })
148 | ```
149 |
--------------------------------------------------------------------------------
/v2/data-props/remembering-state.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Remembering State
3 | ---
4 |
5 | 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.
6 |
7 | 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.
8 |
9 | To mitigate this issue, you can tell Inertia which local component state to save in the browser history.
10 |
11 | ## Saving Local State
12 |
13 | To save local component state to the history state, use the `useRemember` feature to tell Inertia which data it should remember.
14 |
15 |
16 |
17 | ```js Vue icon="vuejs"
18 | import { useRemember } from '@inertiajs/vue3'
19 |
20 | const form = useRemember({
21 | first_name: null,
22 | last_name: null,
23 | })
24 | ```
25 |
26 | ```jsx React icon="react"
27 | import { useRemember } from '@inertiajs/react'
28 |
29 | export default function Profile() {
30 | const [formState, setFormState] = useRemember({
31 | first_name: null,
32 | last_name: null,
33 | // ...
34 | })
35 |
36 | // ...
37 | }
38 | ```
39 |
40 | ```js Svelte icon="s"
41 | import { useRemember } from '@inertiajs/svelte'
42 |
43 | const form = useRemember({
44 | first_name: null,
45 | last_name: null,
46 | })
47 |
48 | // ...
49 | ```
50 |
51 |
52 |
53 | 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.
54 |
55 | ## Multiple Components
56 |
57 | 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.
58 |
59 |
60 |
61 | ```js Vue icon="vuejs"
62 | import { useRemember } from '@inertiajs/vue3'
63 |
64 | const form = useRemember({
65 | first_name: null,
66 | last_name: null,
67 | }, 'Users/Create')
68 | ```
69 |
70 | ```jsx React icon="react"
71 | import { useRemember } from '@inertiajs/react'
72 |
73 | export default function Profile() {
74 | const [formState, setFormState] = useRemember({
75 | first_name: null,
76 | last_name: null,
77 | }, 'Users/Create')
78 | }
79 | ```
80 |
81 | ```js Svelte icon="s"
82 | import { page, useRemember } from '@inertiajs/svelte'
83 |
84 | const form = useRemember({
85 | first_name: null,
86 | last_name: null,
87 | }, 'Users/Create')
88 | ```
89 |
90 |
91 |
92 | 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.
93 |
94 |
95 |
96 | ```js Vue icon="vuejs"
97 | import { useRemember } from '@inertiajs/vue3'
98 |
99 | const props = defineProps({ user: Object })
100 |
101 | const form = useRemember({
102 | first_name: null,
103 | last_name: null,
104 | }, `Users/Edit:${props.user.id}`)
105 | ```
106 |
107 | ```jsx React icon="react"
108 | import { useRemember } from '@inertiajs/react'
109 |
110 | export default function Profile() {
111 | const [formState, setFormState] = useRemember({
112 | first_name: props.user.first_name,
113 | last_name: props.user.last_name,
114 | }, `Users/Edit:${this.user.id}`)
115 | }
116 | ```
117 |
118 | ```js Svelte icon="s"
119 | import { page, useRemember } from '@inertiajs/svelte'
120 |
121 | const form = useRemember({
122 | first_name: $page.props.user.first_name,
123 | last_name: $page.props.user.last_name,
124 | }, `Users/Edit:${$page.props.user.id}`)
125 | ```
126 |
127 |
128 |
129 | ## Form Helper
130 |
131 | If you're using the [Inertia form helper](/v2/the-basics/forms#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.
132 |
133 |
134 |
135 | ```js Vue icon="vuejs"
136 | import { useForm } from '@inertiajs/vue3'
137 |
138 | const form = useForm('CreateUser', data)
139 | const form = useForm(`EditUser:${props.user.id}`, data)
140 | ```
141 |
142 | ```js React icon="react"
143 | import { useForm } from '@inertiajs/react'
144 |
145 | const form = useForm('CreateUser', data)
146 | const form = useForm(`EditUser:${user.id}`, data)
147 | ```
148 |
149 | ```js Svelte icon="s"
150 | import { useForm } from '@inertiajs/svelte'
151 |
152 | const form = useForm('CreateUser', data)
153 | const form = useForm(`EditUser:${user.id}`, data)
154 | ```
155 |
156 |
157 |
158 | ## Manually Saving State
159 |
160 | The `useRemember` hook watches for data changes and automatically saves those changes to the history state. Then, Inertia will restore the data on page load.
161 |
162 | However, it's also possible to manage this manually using the underlying `remember()` and `restore()` methods exposed by Inertia.
163 |
164 |
165 |
166 | ```js Vue icon="vuejs"
167 | import { router } from '@inertiajs/vue3'
168 |
169 | // Save local component state to history state
170 | router.remember(data, 'my-key')
171 |
172 | // Restore local component state from history state
173 | let data = router.restore('my-key')
174 | ```
175 |
176 | ```js React icon="react"
177 | import { router } from '@inertiajs/react'
178 |
179 | // Save local component state to history state
180 | router.remember(data, 'my-key')
181 |
182 | // Restore local component state from history state
183 | let data = router.restore('my-key')
184 | ```
185 |
186 | ```js Svelte icon="s"
187 | import { router } from '@inertiajs/svelte'
188 |
189 | // Save local component state to history state
190 | router.remember(data, 'my-key')
191 |
192 | // Restore local component state from history state
193 | let data = router.restore('my-key')
194 | ```
195 |
196 |
197 |
--------------------------------------------------------------------------------
/v2/the-basics/file-uploads.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: File Uploads
3 | ---
4 |
5 | ## `FormData` Conversion
6 |
7 | 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.
8 |
9 | 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.
10 |
11 |
12 |
13 | ```js Vue icon="vuejs"
14 | import { router } from '@inertiajs/vue3'
15 |
16 | router.post('/users', data, {
17 | forceFormData: true,
18 | })
19 | ```
20 |
21 | ```js React icon="react"
22 | import { router } from '@inertiajs/react'
23 |
24 | router.post('/users', data, {
25 | forceFormData: true,
26 | })
27 | ```
28 |
29 | ```js Svelte icon="s"
30 | import { router } from '@inertiajs/svelte'
31 |
32 | router.post('/users', data, {
33 | forceFormData: true,
34 | })
35 | ```
36 |
37 |
38 |
39 | You can learn more about the `FormData` interface via its [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/FormData).
40 |
41 | ## File Upload Example
42 |
43 | Let's examine a complete file upload example using Inertia. This example includes both a `name` text input and an `avatar` file input.
44 |
45 |
46 |
47 | ```vue Vue icon="vuejs"
48 |
60 |
61 |
62 |
70 |
71 | ```
72 |
73 | ```jsx React icon="react"
74 | import { useForm } from '@inertiajs/react'
75 |
76 | const { data, setData, post, progress } = useForm({
77 | name: null,
78 | avatar: null,
79 | })
80 |
81 | function submit(e) {
82 | e.preventDefault()
83 | post('/users')
84 | }
85 |
86 | return (
87 |
97 | )
98 | ```
99 |
100 | ```svelte Svelte 4 icon="s"
101 |
113 |
114 |
124 | ```
125 |
126 | ```svelte Svelte 5 icon="s"
127 |
140 |
141 |
151 | ```
152 |
153 |
154 |
155 | This example uses the [Inertia form helper](/v2/the-basics/forms#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](/v2/the-basics/manual-visits) as well.
156 |
157 | ## Multipart Limitations
158 |
159 | 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.
160 |
161 | However, some frameworks, such as [Laravel](https://laravel.com/docs/routing#form-method-spoofing) and [Rails ](https://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark), 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.
162 |
163 |
164 |
165 | ```js Vue icon="vuejs"
166 | import { router } from '@inertiajs/vue3'
167 |
168 | router.post(`/users/${user.id}`, {
169 | _method: 'put',
170 | avatar: form.avatar,
171 | })
172 | ```
173 |
174 | ```js React icon="react"
175 | import { router } from '@inertiajs/react'
176 |
177 | router.post(`/users/${user.id}`, {
178 | _method: 'put',
179 | avatar: form.avatar,
180 | })
181 | ```
182 |
183 | ```js Svelte icon="s"
184 | import { router } from '@inertiajs/svelte'
185 |
186 | router.post(`/users/${user.id}`, {
187 | _method: 'put',
188 | avatar: form.avatar,
189 | })
190 | ```
191 |
192 |
193 |
--------------------------------------------------------------------------------
/v1/advanced/error-handling.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Error Handling
3 | ---
4 |
5 | This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v2 docs](/v2) for the latest information.
6 |
7 | ## Development
8 |
9 | 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](https://github.com/facade/ignition), a beautiful error reporting tool which displays a nicely formatted stack trace in local development.
10 |
11 | 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.
12 |
13 | 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.
14 |
15 | ## Production
16 |
17 | 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.
18 |
19 | When building Laravel applications, you can accomplish this by using the `respond` exception method in your application's `bootstrap/app.php` file.
20 |
21 | ```php
22 | use Illuminate\Http\Request;
23 | use Symfony\Component\HttpFoundation\Response;
24 | use Inertia\Inertia;
25 |
26 | ->withExceptions(function (Exceptions $exceptions) {
27 | $exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
28 | if (! app()->environment(['local', 'testing']) && in_array($response->getStatusCode(), [500, 503, 404, 403])) {
29 | return Inertia::render('Error', ['status' => $response->getStatusCode()])
30 | ->toResponse($request)
31 | ->setStatusCode($response->getStatusCode());
32 | } elseif ($response->getStatusCode() === 419) {
33 | return back()->with([
34 | 'message' => 'The page expired, please try again.',
35 | ]);
36 | }
37 |
38 | return $response;
39 | });
40 | })
41 | ```
42 |
43 | 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.
44 |
45 |
46 |
47 | ```vue Vue 2 icon="vuejs"
48 |
49 |
163 | ```
164 |
165 |
166 |
--------------------------------------------------------------------------------
/v2/advanced/error-handling.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Error Handling
3 | ---
4 |
5 | ## Development
6 |
7 | 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 a beautiful error reporting tool which displays a nicely formatted stack trace in local development.
8 |
9 | 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.
10 |
11 | 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.
12 |
13 | ## Dialog Element
14 |
15 | By default, Inertia displays error modals using a custom `
` overlay. However, you can opt-in to using the native HTML `