## 1. Project Overview & Quickstart (inertiajs/inertia)

## File: packages/vue3/readme.md

# Inertia.js Vue 3 Adapter

Visit [inertiajs.com](https://inertiajs.com/) to learn more.

---

## File: packages/svelte/readme.md

# Inertia.js Svelte Adapter

Visit [inertiajs.com](https://inertiajs.com/) to learn more.

---

## File: packages/react/readme.md

# Inertia.js React Adapter

Visit [inertiajs.com](https://inertiajs.com/) to learn more.

---

## File: packages/core/readme.md

# Inertia.js

Inertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers.

Visit [inertiajs.com](https://inertiajs.com/) to learn more.

---

## File: playgrounds/vue3/README.md

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

---

## File: playgrounds/svelte5/README.md

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

---

## File: playgrounds/svelte4/README.md

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

---

## File: playgrounds/react/README.md

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

## 2. Official Technical Reference & Guides (inertiajs/docs)

## File: README.md

## Development

Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command:

```
npm i -g mint
```

Run the following command at the root of your documentation, where your `docs.json` is located:

```
mint dev
```

View your local preview at `http://localhost:3000`.

### Resources

- [Mintlify documentation](https://mintlify.com/docs)

---

## File: docs.json

{
    "$schema": "https://mintlify.com/docs.json",
    "theme": "mint",
    "name": "Inertia.js Documentation",
    "colors": {
        "primary": "#2563EB",
        "light": "#2563EB",
        "dark": "#2563EB"
    },
    "favicon": "/favicon.svg",
    "navigation": {
        "global": {},
        "versions": [
            {
                "version": "3.x",
                "groups": [
                    {
                        "group": "Getting Started",
                        "pages": [
                            "v3/getting-started/index",
                            "v3/getting-started/demo-application",
                            "v3/getting-started/upgrade-guide"
                        ]
                    },
                    {
                        "group": "Installation",
                        "pages": [
                            "v3/installation/server-side-setup",
                            "v3/installation/client-side-setup"
                        ]
                    },
                    {
                        "group": "Core Concepts",
                        "pages": [
                            "v3/core-concepts/who-is-it-for",
                            "v3/core-concepts/how-it-works",
                            "v3/core-concepts/the-protocol"
                        ]
                    },
                    {
                        "group": "The Basics",
                        "pages": [
                            "v3/the-basics/pages",
                            "v3/the-basics/responses",
                            "v3/the-basics/redirects",
                            "v3/the-basics/routing",
                            "v3/the-basics/title-and-meta",
                            "v3/the-basics/links",
                            "v3/the-basics/manual-visits",
                            "v3/the-basics/instant-visits",
                            "v3/the-basics/forms",
                            "v3/the-basics/http-requests",
                            "v3/the-basics/optimistic-updates",
                            "v3/the-basics/file-uploads",
                            "v3/the-basics/validation",
                            "v3/the-basics/layouts",
                            "v3/the-basics/view-transitions"
                        ]
                    },
                    {
                        "group": "Data & Props",
                        "pages": [
                            "v3/data-props/shared-data",
                            "v3/data-props/flash-data",
                            "v3/data-props/partial-reloads",
                            "v3/data-props/deferred-props",
                            "v3/data-props/merging-props",
                            "v3/data-props/once-props",
                            "v3/data-props/polling",
                            "v3/data-props/prefetching",
                            "v3/data-props/load-when-visible",
                            "v3/data-props/infinite-scroll",
                            "v3/data-props/remembering-state"
                        ]
                    },
                    {
                        "group": "Security",
                        "pages": [
                            "v3/security/authentication",
                            "v3/security/authorization",
                            "v3/security/csrf-protection",
                            "v3/security/history-encryption"
                        ]
                    },
                    {
                        "group": "Advanced",
                        "pages": [
                            "v3/advanced/asset-versioning",
                            "v3/advanced/big-integers",
                            "v3/advanced/code-splitting",
                            "v3/advanced/devtools",
                            "v3/advanced/error-handling",
                            "v3/advanced/events",
                            "v3/advanced/progress-indicators",
                            "v3/advanced/scroll-management",
                            "v3/advanced/server-side-rendering",
                            "v3/advanced/testing",
                            "v3/advanced/typescript"
                        ]
                    }
                ]
            },
            {
                "version": "2.x",
                "groups": [
                    {
                        "group": "Getting Started",
                        "pages": [
                            "v2/getting-started/index",
                            "v2/getting-started/demo-application",
                            "v2/getting-started/upgrade-guide"
                        ]
                    },
                    {
                        "group": "Installation",
                        "pages": [
                            "v2/installation/server-side-setup",
                            "v2/installation/client-side-setup"
                        ]
                    },
                    {
                        "group": "Core Concepts",
                        "pages": [
                            "v2/core-concepts/who-is-it-for",
                            "v2/core-concepts/how-it-works",
                            "v2/core-concepts/the-protocol"
                        ]
                    },
                    {
                        "group": "The Basics",
                        "pages": [
                            "v2/the-basics/pages",
                            "v2/the-basics/responses",
                            "v2/the-basics/redirects",
                            "v2/the-basics/routing",
                            "v2/the-basics/title-and-meta",
                            "v2/the-basics/links",
                            "v2/the-basics/manual-visits",
                            "v2/the-basics/forms",
                            "v2/the-basics/file-uploads",
                            "v2/the-basics/validation",
                            "v2/the-basics/view-transitions"
                        ]
                    },
                    {
                        "group": "Data & Props",
                        "pages": [
                            "v2/data-props/shared-data",
                            "v2/data-props/flash-data",
                            "v2/data-props/partial-reloads",
                            "v2/data-props/deferred-props",
                            "v2/data-props/merging-props",
                            "v2/data-props/once-props",
                            "v2/data-props/polling",
                            "v2/data-props/prefetching",
                            "v2/data-props/load-when-visible",
                            "v2/data-props/infinite-scroll",
                            "v2/data-props/remembering-state"
                        ]
                    },
                    {
                        "group": "Security",
                        "pages": [
                            "v2/security/authentication",
                            "v2/security/authorization",
                            "v2/security/csrf-protection",
                            "v2/security/history-encryption"
                        ]
                    },
                    {
                        "group": "Advanced",
                        "pages": [
                            "v2/advanced/asset-versioning",
                            "v2/advanced/code-splitting",
                            "v2/advanced/error-handling",
                            "v2/advanced/events",
                            "v2/advanced/progress-indicators",
                            "v2/advanced/scroll-management",
                            "v2/advanced/server-side-rendering",
                            "v2/advanced/testing",
                            "v2/advanced/typescript"
                        ]
                    }
                ]
            },
            {
                "version": "1.x",
                "groups": [
                    {
                        "group": "Getting Started",
                        "pages": [
                            "v1/getting-started/index",
                            "v1/getting-started/demo-application",
                            "v1/getting-started/upgrade-guide"
                        ]
                    },
                    {
                        "group": "Installation",
                        "pages": [
                            "v1/installation/server-side-setup",
                            "v1/installation/client-side-setup"
                        ]
                    },
                    {
                        "group": "Core Concepts",
                        "pages": [
                            "v1/core-concepts/who-is-it-for",
                            "v1/core-concepts/how-it-works",
                            "v1/core-concepts/the-protocol"
                        ]
                    },
                    {
                        "group": "The Basics",
                        "pages": [
                            "v1/the-basics/pages",
                            "v1/the-basics/responses",
                            "v1/the-basics/redirects",
                            "v1/the-basics/routing",
                            "v1/the-basics/title-and-meta",
                            "v1/the-basics/links",
                            "v1/the-basics/manual-visits",
                            "v1/the-basics/forms",
                            "v1/the-basics/file-uploads",
                            "v1/the-basics/validation",
                            "v1/the-basics/shared-data"
                        ]
                    },
                    {
                        "group": "Advanced",
                        "pages": [
                            "v1/advanced/events",
                            "v1/advanced/testing",
                            "v1/advanced/partial-reloads",
                            "v1/advanced/scroll-management",
                            "v1/advanced/authentication",
                            "v1/advanced/authorization",
                            "v1/advanced/csrf-protection",
                            "v1/advanced/error-handling",
                            "v1/advanced/asset-versioning",
                            "v1/advanced/progress-indicators",
                            "v1/advanced/remembering-state",
                            "v1/advanced/server-side-rendering"
                        ]
                    }
                ]
            }
        ]
    },
    "logo": {
        "light": "/logo/light.svg",
        "dark": "/logo/dark.svg"
    },
    "navbar": {},
    "contextual": {
        "options": [
            "copy",
            "view",
            "chatgpt",
            "claude",
            "perplexity",
            "mcp",
            "cursor",
            "vscode"
        ]
    },
    "footer": {
        "socials": {
            "x": "https://x.com/inertiajs",
            "github": "https://github.com/inertiajs"
        }
    },
    "redirects": [
        {
            "source": "/index",
            "destination": "/v3/getting-started/index"
        },
        {
            "source": "/demo-application",
            "destination": "/v3/getting-started/demo-application"
        },
        {
            "source": "/upgrade-guide",
            "destination": "/v3/getting-started/upgrade-guide"
        },
        {
            "source": "/server-side-setup",
            "destination": "/v3/installation/server-side-setup"
        },
        {
            "source": "/client-side-setup",
            "destination": "/v3/installation/client-side-setup"
        },
        {
            "source": "/who-is-it-for",
            "destination": "/v3/core-concepts/who-is-it-for"
        },
        {
            "source": "/how-it-works",
            "destination": "/v3/core-concepts/how-it-works"
        },
        {
            "source": "/the-protocol",
            "destination": "/v3/core-concepts/the-protocol"
        },
        {
            "source": "/pages",
            "destination": "/v3/the-basics/pages"
        },
        {
            "source": "/responses",
            "destination": "/v3/the-basics/responses"
        },
        {
            "source": "/devtools",
            "destination": "/v3/advanced/devtools"
        },
        {
            "source": "/devtools-protocol",
            "destination": "/v3/advanced/devtools-protocol"
        },
        {
            "source": "/redirects",
            "destination": "/v3/the-basics/redirects"
        },
        {
            "source": "/routing",
            "destination": "/v3/the-basics/routing"
        },
        {
            "source": "/title-and-meta",
            "destination": "/v3/the-basics/title-and-meta"
        },
        {
            "source": "/links",
            "destination": "/v3/the-basics/links"
        },
        {
            "source": "/manual-visits",
            "destination": "/v3/the-basics/manual-visits"
        },
        {
            "source": "/forms",
            "destination": "/v3/the-basics/forms"
        },
        {
            "source": "/file-uploads",
            "destination": "/v3/the-basics/file-uploads"
        },
        {
            "source": "/validation",
            "destination": "/v3/the-basics/validation"
        },
        {
            "source": "/view-transitions",
            "destination": "/v3/the-basics/view-transitions"
        },
        {
            "source": "/instant-visits",
            "destination": "/v3/the-basics/instant-visits"
        },
        {
            "source": "/http-requests",
            "destination": "/v3/the-basics/http-requests"
        },
        {
            "source": "/optimistic-updates",
            "destination": "/v3/the-basics/optimistic-updates"
        },
        {
            "source": "/layout-props",
            "destination": "/v3/the-basics/layouts"
        },
        {
            "source": "/v3/the-basics/layout-props",
            "destination": "/v3/the-basics/layouts"
        },
        {
            "source": "/shared-data",
            "destination": "/v3/data-props/shared-data"
        },
        {
            "source": "/partial-reloads",
            "destination": "/v3/data-props/partial-reloads"
        },
        {
            "source": "/deferred-props",
            "destination": "/v3/data-props/deferred-props"
        },
        {
            "source": "/merging-props",
            "destination": "/v3/data-props/merging-props"
        },
        {
            "source": "/polling",
            "destination": "/v3/data-props/polling"
        },
        {
            "source": "/prefetching",
            "destination": "/v3/data-props/prefetching"
        },
        {
            "source": "/load-when-visible",
            "destination": "/v3/data-props/load-when-visible"
        },
        {
            "source": "/infinite-scroll",
            "destination": "/v3/data-props/infinite-scroll"
        },
        {
            "source": "/remembering-state",
            "destination": "/v3/data-props/remembering-state"
        },
        {
            "source": "/authentication",
            "destination": "/v3/security/authentication"
        },
        {
            "source": "/authorization",
            "destination": "/v3/security/authorization"
        },
        {
            "source": "/csrf-protection",
            "destination": "/v3/security/csrf-protection"
        },
        {
            "source": "/history-encryption",
            "destination": "/v3/security/history-encryption"
        },
        {
            "source": "/asset-versioning",
            "destination": "/v3/advanced/asset-versioning"
        },
        {
            "source": "/code-splitting",
            "destination": "/v3/advanced/code-splitting"
        },
        {
            "source": "/error-handling",
            "destination": "/v3/advanced/error-handling"
        },
        {
            "source": "/events",
            "destination": "/v3/advanced/events"
        },
        {
            "source": "/progress-indicators",
            "destination": "/v3/advanced/progress-indicators"
        },
        {
            "source": "/scroll-management",
            "destination": "/v3/advanced/scroll-management"
        },
        {
            "source": "/server-side-rendering",
            "destination": "/v3/advanced/server-side-rendering"
        },
        {
            "source": "/testing",
            "destination": "/v3/advanced/testing"
        },
        {
            "source": "/typescript",
            "destination": "/v3/advanced/typescript"
        }
    ]
}

---

## File: snippets/v1-eol-warning.mdx

<Warning>This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v3 docs](/v3/getting-started/index).</Warning>

---

## File: snippets/v2-upgrade-warning.mdx

<Warning>You are viewing the documentation for Inertia.js v2. Inertia.js v3 has been released and is now the default version. Please visit the [upgrade guide](/v3/getting-started/upgrade-guide) to get started.</Warning>

---

## File: v1/advanced/asset-versioning.mdx

---
title: Asset Versioning
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

## Configuration

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

Typically, your application's asset version can be specified within the `version` method of the Inertia `HandleInertiaRequests` middleware.

```php
class HandleInertiaRequests extends Middleware
{
    public function version(Request $request)
    {
        return parent::version($request);
    }
}
```

Alternatively, the asset version can be provided manually using the `Inertia::version()` method.

```php
use Inertia\Inertia;

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

## Cache Busting

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

If you're using Laravel Mix, you can do this automatically by enabling [versioning](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.

---

## File: v1/advanced/authentication.mdx

---
title: Authentication
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

<Card
    icon="laravel"
    title="Laravel Starter Kits"
    href="https://laravel.com/docs/starter-kits"
    arrow="true"
    cta="Start building"
>
Laravel's starter kits provide out-of-the-box scaffolding for new Inertia applications, including authentication.
</Card>

---

## File: v1/advanced/authorization.mdx

---
title: Authorization
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

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

---

## File: v1/advanced/csrf-protection.mdx

---
title: CSRF Protection
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Making Requests

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

If your server-side framework includes cross-site request forgery (CSRF) protection, you'll need to ensure that each Inertia requests includes the necessary CSRF token for `POST`, `PUT`, `PATCH`, and `DELETE` requests.

Of course, as already discussed, some server-side frameworks such as Laravel automatically handle the inclusion of the CSRF token when making requests. **Therefore, no additional configuration is required when using one of these frameworks.**

However, if you need to handle CSRF protection manually, one approach is to include the CSRF token as a prop on every response. You can then use the token when making Inertia requests.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post('/users', {
    _token: this.$page.props.csrf_token,
    name: 'John Doe',
    email: 'john.doe@example.com',
})
```

```js Vue 3 icon="vuejs"
import { router, usePage } from '@inertiajs/vue3'

const page = usePage()

router.post('/users', {
    _token: page.props.csrf_token,
    name: 'John Doe',
    email: 'john.doe@example.com',
})
```

```js React icon="react"
import { router, usePage } from '@inertiajs/react'

const props = usePage().props

router.post('/users', {
    _token: props.csrf_token,
    name: 'John Doe',
    email: 'john.doe@example.com',
})
```

```js Svelte icon="s"
import { page, router } from '@inertiajs/svelte'

router.post('/users', {
    _token: $page.props.csrf_token,
    name: 'John Doe',
    email: 'john.doe@example.com',
})
```

</CodeGroup>

You can even use Inertia's [shared data](/v1/the-basics/shared-data) functionality to automatically include the `csrf_token` with each response.

However, a better approach is to use the CSRF functionality already built into [axios](https://github.com/axios/axios) for this. Axios is the HTTP library that Inertia uses under the hood.

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

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

## Handling Mismatches

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

<video controls></video>

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.

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.

```php
use Symfony\Component\HttpFoundation\Response;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response) {
        if ($response->getStatusCode() === 419) {
            return back()->with([
                'message' => 'The page expired, please try again.',
            ]);
        }

        return $response;
    });
});
```

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

<video controls></video>

---

## File: v1/advanced/error-handling.mdx

---
title: Error Handling
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Development

One of the advantages to working with a robust server-side framework is the built-in exception handling you get for free. For example, Laravel ships with [Ignition](https://github.com/facade/ignition), a beautiful error reporting tool which displays a nicely formatted stack trace in local development.

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

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

## Production

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

When building Laravel applications, you can accomplish this by using the `respond` exception method in your application's `bootstrap/app.php` file.

```php
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Inertia\Inertia;

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

        return $response;
    });
})
```

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <div>
        <H1>{{ title }}</H1>
        <div>{{ description }}</div>
    </div>
</template>

<script>
export default {
    props: {
        status: Number,
    },
    computed: {
        title() {
            return {
                503: '503: Service Unavailable',
                500: '500: Server Error',
                404: '404: Page Not Found',
                403: '403: Forbidden',
            }[this.status]
        },
        description() {
            return {
                503: 'Sorry, we are doing some maintenance. Please check back soon.',
                500: 'Whoops, something went wrong on our servers.',
                404: 'Sorry, the page you are looking for could not be found.',
                403: 'Sorry, you are forbidden from accessing this page.',
            }[this.status]
        },
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { computed } from 'vue'

const props = defineProps({ status: Number })

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

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

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

```jsx React icon="react"
export default function ErrorPage({ status }) {
    const title = {
        503: '503: Service Unavailable',
        500: '500: Server Error',
        404: '404: Page Not Found',
        403: '403: Forbidden',
    }[status]

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

    return (
        <div>
            <H1>{title}</H1>
            <div>{description}</div>
        </div>
    )
}
```

```html Svelte icon="s"
<script>
    export let status

    $: title = {
        503: '503: Service Unavailable',
        500: '500: Server Error',
        404: '404: Page Not Found',
        403: '403: Forbidden',
    }[status]

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

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

</CodeGroup>

---

## File: v1/advanced/events.mdx

---
title: Events
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

## Registering Listeners

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

document.addEventListener('inertia:start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

document.addEventListener('inertia:start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

document.addEventListener('inertia:start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

document.addEventListener('inertia:start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

</CodeGroup>

## Removing Listeners

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

let removeStartEventListener = router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})

// Remove the listener...
removeStartEventListener()
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

let removeStartEventListener = router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})

// Remove the listener...
removeStartEventListener()
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

let removeStartEventListener = router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})

// Remove the listener...
removeStartEventListener()
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

let removeStartEventListener = router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})

// Remove the listener...
removeStartEventListener()
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

export default {
    mounted() {
        this.$once(
            'hook:destroyed',
            router.on('start', (event) => {
                console.log(`Starting a visit to ${event.detail.visit.url}`)
            })
        )
    },
}
```

```vue Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'
import { onUnmounted } from 'vue'

onUnmounted(
    router.on('start', (event) => {
        console.log(`Starting a visit to ${event.detail.visit.url}`)
    })
)
```

```jsx React icon="react"
import { useEffect } from 'react'
import { router } from '@inertiajs/react'

useEffect(() => {
    return router.on('start', (event) => {
        console.log(`Starting a visit to ${event.detail.visit.url}`)
    })
}, [])
```

```svelte Svelte icon="s"
import { router } from '@inertiajs/svelte'
import { onMount } from 'svelte'

onMount(() => {
    return router.on('start', (event) => {
        console.log(`Starting a visit to ${event.detail.visit.url}`)
    })
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

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

// Remove the listener...
document.removeEventListener('inertia:start', startEventListener)
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

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

// Remove the listener...
document.removeEventListener('inertia:start', startEventListener)
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

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

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

// Remove the listener...
document.removeEventListener('inertia:start', startEventListener)
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

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

// Remove the listener...
document.removeEventListener('inertia:start', startEventListener)
```

</CodeGroup>

## Cancelling Events

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('before', (event) => {
    if (!confirm('Are you sure you want to navigate away?')) {
        event.preventDefault()
    }
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('before', (event) => {
    if (!confirm('Are you sure you want to navigate away?')) {
        event.preventDefault()
    }
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('before', (event) => {
    if (!confirm('Are you sure you want to navigate away?')) {
        event.preventDefault()
    }
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('before', (event) => {
    if (!confirm('Are you sure you want to navigate away?')) {
        event.preventDefault()
    }
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

</CodeGroup>

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

## Before

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('before', (event) => {
    console.log(`About to make a visit to ${event.detail.visit.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('before', (event) => {
    console.log(`About to make a visit to ${event.detail.visit.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('before', (event) => {
    console.log(`About to make a visit to ${event.detail.visit.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('before', (event) => {
    console.log(`About to make a visit to ${event.detail.visit.url}`)
})
```

</CodeGroup>

The primary purpose of this event is to allow you to prevent a visit from happening.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('before', (event) => {
    return confirm('Are you sure you want to navigate away?')
})
```

</CodeGroup>

## Start

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('start', (event) => {
    console.log(`Starting a visit to ${event.detail.visit.url}`)
})
```

</CodeGroup>

The `start` event is not cancelable.

## Progress

The `progress` event fires as progress increments during file uploads.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('progress', (event) => {
    this.form.progress = event.detail.progress.percentage
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('progress', (event) => {
    this.form.progress = event.detail.progress.percentage
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('progress', (event) => {
    this.form.progress = event.detail.progress.percentage
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('progress', (event) => {
    this.form.progress = event.detail.progress.percentage
})
```

</CodeGroup>

The `progress` event is not cancelable.

## Success

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('success', (event) => {
    console.log(`Successfully made a visit to ${event.detail.page.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('success', (event) => {
    console.log(`Successfully made a visit to ${event.detail.page.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('success', (event) => {
    console.log(`Successfully made a visit to ${event.detail.page.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('success', (event) => {
    console.log(`Successfully made a visit to ${event.detail.page.url}`)
})
```

</CodeGroup>

The `success` event is not cancelable.

## Error

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('error', (errors) => {
    console.log(errors)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('error', (errors) => {
    console.log(errors)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('error', (errors) => {
    console.log(errors)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('error', (errors) => {
    console.log(errors)
})
```

</CodeGroup>

The `error` event is not cancelable.

## Invalid

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

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('invalid', (event) => {
    console.log(`An invalid Inertia response was received.`)
    console.log(event.detail.response)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('invalid', (event) => {
    console.log(`An invalid Inertia response was received.`)
    console.log(event.detail.response)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('invalid', (event) => {
    console.log(`An invalid Inertia response was received.`)
    console.log(event.detail.response)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('invalid', (event) => {
    console.log(`An invalid Inertia response was received.`)
    console.log(event.detail.response)
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

    // Handle the invalid response yourself...
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

    // Handle the invalid response yourself...
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

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

    // Handle the invalid response yourself...
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

    // Handle the invalid response yourself...
})
```

</CodeGroup>

## Exception

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('exception', (event) => {
    console.log(`An unexpected error occurred during an Inertia visit.`)
    console.log(event.detail.error)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('exception', (event) => {
    console.log(`An unexpected error occurred during an Inertia visit.`)
    console.log(event.detail.error)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('exception', (event) => {
    console.log(`An unexpected error occurred during an Inertia visit.`)
    console.log(event.detail.error)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('exception', (event) => {
    console.log(`An unexpected error occurred during an Inertia visit.`)
    console.log(event.detail.error)
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('exception', (event) => {
    event.preventDefault()
    // Handle the error yourself
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('exception', (event) => {
    event.preventDefault()
    // Handle the error yourself
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('exception', (event) => {
    event.preventDefault()
    // Handle the error yourself
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('exception', (event) => {
    event.preventDefault()
    // Handle the error yourself
})
```

</CodeGroup>

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

## Finish

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('finish', (event) => {
    NProgress.done()
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('finish', (event) => {
    NProgress.done()
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('finish', (event) => {
    NProgress.done()
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('finish', (event) => {
    NProgress.done()
})
```

</CodeGroup>

The `finish` event is not cancelable.

## Navigate

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.on('navigate', (event) => {
    console.log(`Navigated to ${event.detail.page.url}`)
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.on('navigate', (event) => {
    console.log(`Navigated to ${event.detail.page.url}`)
})
```

```jsx React icon="react"
import { router } from '@inertiajs/react'

router.on('navigate', (event) => {
    console.log(`Navigated to ${event.detail.page.url}`)
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.on('navigate', (event) => {
    console.log(`Navigated to ${event.detail.page.url}`)
})
```

</CodeGroup>

The `navigate` event is not cancelable.

## Event Callbacks

In addition to the global events described throughout this page, Inertia also provides a number of [event callbacks](/manual-visits#event-callbacks) that fire when manually making Inertia visits.

---

## File: v1/advanced/partial-reloads.mdx

---
title: Partial Reloads
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

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

## Only Certain Props

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

## Except Certain Props

In addition to the `only` visit option you can also use the `except` option to specify which data the server should exclude. This option should also be an array of keys which correspond to the keys of the props.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

## Router Shorthand

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

## Using Links

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/users?active=true" use:inertia="{{ only: ['users'] }}">Show active</a>

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

</CodeGroup>

## Lazy Data Evaluation

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

```php
return Inertia::render('Users/Index', [
    'users' => fn () => User::all(),
    'companies' => fn () => Company::all(),
]);
```

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

Additionally, Inertia provides an `Inertia::lazy()` method to specify that a prop should never be included unless explicitly requested using the `only` option:

```php
return Inertia::render('Users/Index', [
    'users' => Inertia::lazy(fn () => User::all()),
]);
```

On the inverse, you can use the `Inertia::always()` method to specify that a prop should always be included, even if it has not been explicitly required in a partial reload.

```php
return Inertia::render('Users/Index', [
    'users' => Inertia::always(User::all()),
]);
```

Here's a summary of each approach:

```php
return Inertia::render('Users/Index', [
    // ALWAYS included on standard visits
    // OPTIONALLY included on partial reloads
    // ALWAYS evaluated
    'users' => User::all(),

    // ALWAYS included on standard visits
    // OPTIONALLY included on partial reloads
    // ONLY evaluated when needed
    'users' => fn () => User::all(),

    // NEVER included on standard visits
    // OPTIONALLY included on partial reloads
    // ONLY evaluated when needed
    'users' => Inertia::lazy(fn () => User::all()),

    // ALWAYS included on standard visits
    // ALWAYS included on partial reloads
    // ALWAYS evaluated
    'users' => Inertia::always(User::all()),
]);
```

---

## File: v1/advanced/progress-indicators.mdx

---
title: Progress Indicators
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

## Default

Inertia's default progress indicator is a light-weight wrapper around the [NProgress](https://ricostacruz.com/nprogress/) library. You can customize it via the `progress` property of the `createInertiaApp()` function.

```js
createInertiaApp({
progress: {
// The delay after which the progress bar will appear, in milliseconds...
delay: 250,
// The color of the progress bar...
color: '#29d',
// Whether to include the default NProgress styles...
includeCSS: true,
// Whether the NProgress spinner will be shown...
showSpinner: false,
},
// ...
})
```

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

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

## Custom

It's also possible to setup your own custom page loading indicators using Inertia [events](/v1/advanced/events). Let's explore how to do this using the [NProgress](https://ricostacruz.com/nprogress/) library as an example.

First, disable Inertia's default loading indicator.

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

Next, install the NProgress library.

```bash
npm install nprogress
```

After installation, you'll need to add the NProgress [styles](https://github.com/rstacruz/nprogress/blob/master/nprogress.css) to your project. You can do this using a CDN hosted copy of the styles.

```html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" />
```

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import NProgress from 'nprogress'
import { router } from '@inertiajs/vue2'
```

```js Vue 3 icon="vuejs"
import NProgress from 'nprogress'
import { router } from '@inertiajs/vue3'
```

```js React icon="react"
import NProgress from 'nprogress'
import { router } from '@inertiajs/react'
```

```js Svelte icon="s"
import NProgress from 'nprogress'
import { router } from '@inertiajs/svelte'
```

</CodeGroup>

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

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

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

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

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

### Handling Cancelled Visits

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

We can accomplish this by inspecting the `event.detail.visit` object that's provided to the finish event.

```js
router.on('finish', (event) => {
if (event.detail.visit.completed) {
NProgress.done()
} else if (event.detail.visit.interrupted) {
NProgress.set(0)
} else if (event.detail.visit.cancelled) {
NProgress.done()
NProgress.remove()
}
})
```

### File Upload Progress

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

```js
router.on('progress', (event) => {
if (event.detail.progress.percentage) {
NProgress.set((event.detail.progress.percentage / 100) * 0.9)
}
})
```

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

### Loading Indicator Delay

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

To implement the delay behavior, we'll use the `setTimeout` and `clearTimeout` functions. Let's start by defining a variable to keep track of the timeout.

```js
let timeout = null
```

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

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

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

```js
router.on('finish', (event) => {
clearTimeout(timeout)
// ...
})
```

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

```js
router.on('finish', (event) => {
clearTimeout(timeout)
if (!NProgress.isStarted()) {
return
}
// ...
})
```

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

```js
router.on('progress', event => {
if (!NProgress.isStarted()) {
return
}
// ...
}
```

That's it, you now have a beautiful custom page loading indicator!

### Complete Example

For convenience, here is the full source code of the final version of our custom loading indicator.

<CodeGroup>

```js Vue 2 icon="vuejs"
import NProgress from 'nprogress'
import { router } from '@inertiajs/vue2'

let timeout = null

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

router.on('progress', (event) => {
    if (NProgress.isStarted() && event.detail.progress.percentage) {
        NProgress.set((event.detail.progress.percentage / 100) * 0.9)
    }
})

router.on('finish', (event) => {
    clearTimeout(timeout)
    if (!NProgress.isStarted()) {
        return
    } else if (event.detail.visit.completed) {
        NProgress.done()
    } else if (event.detail.visit.interrupted) {
        NProgress.set(0)
    } else if (event.detail.visit.cancelled) {
        NProgress.done()
        NProgress.remove()
    }
})
```

```js Vue 3 icon="vuejs"
import NProgress from 'nprogress'
import { router } from '@inertiajs/vue3'

let timeout = null

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

router.on('progress', (event) => {
    if (NProgress.isStarted() && event.detail.progress.percentage) {
        NProgress.set((event.detail.progress.percentage / 100) * 0.9)
    }
})

router.on('finish', (event) => {
    clearTimeout(timeout)
    if (!NProgress.isStarted()) {
        return
    } else if (event.detail.visit.completed) {
        NProgress.done()
    } else if (event.detail.visit.interrupted) {
        NProgress.set(0)
    } else if (event.detail.visit.cancelled) {
        NProgress.done()
        NProgress.remove()
    }
})
```

```js React icon="react"
import NProgress from 'nprogress'
import { router } from '@inertiajs/react'

let timeout = null

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

router.on('progress', (event) => {
    if (NProgress.isStarted() && event.detail.progress.percentage) {
        NProgress.set((event.detail.progress.percentage / 100) * 0.9)
    }
})

router.on('finish', (event) => {
    clearTimeout(timeout)
    if (!NProgress.isStarted()) {
        return
    } else if (event.detail.visit.completed) {
        NProgress.done()
    } else if (event.detail.visit.interrupted) {
        NProgress.set(0)
    } else if (event.detail.visit.cancelled) {
        NProgress.done()
        NProgress.remove()
    }
})
```

```js Svelte icon="s"
import NProgress from 'nprogress'
import { router } from '@inertiajs/svelte'

let timeout = null

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

router.on('progress', (event) => {
    if (NProgress.isStarted() && event.detail.progress.percentage) {
        NProgress.set((event.detail.progress.percentage / 100) * 0.9)
    }
})

router.on('finish', (event) => {
    clearTimeout(timeout)
    if (!NProgress.isStarted()) {
        return
    } else if (event.detail.visit.completed) {
        NProgress.done()
    } else if (event.detail.visit.interrupted) {
        NProgress.set(0)
    } else if (event.detail.visit.cancelled) {
        NProgress.done()
        NProgress.remove()
    }
})
```

</CodeGroup>

---

## File: v1/advanced/remembering-state.mdx

---
title: Remembering State
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

When navigating browser history, Inertia restores pages using prop data cached in history state. However, Inertia does not restore local page component state since this is beyond its reach. This can lead to outdated pages in your browser history.

For example, if a user partially completes a form, then navigates away, and then returns back, the form will be reset and their work will be lost.

To mitigate this issue, you can tell Inertia which local component state to save in the browser history.

## Saving Local State

To save local component state to the history state, use the `remember` feature to tell Inertia which data it should remember.

<CodeGroup>

```js Vue 2 icon="vuejs"
{
    // Option 1: Object...
    remember: {
        data: ['form'],
    },

    // Option 2: Array...
    remember: ['form'],

    // Option 3: String...
    remember: 'form',

    data() {
        return {
            form: {
                first_name: null,
                last_name: null,
                // ...
            },
        }
    },
}
```

```js Vue 3 icon="vuejs"
import { useRemember } from '@inertiajs/vue3'

const form = useRemember({
    first_name: null,
    last_name: null,
})
```

```jsx React icon="react"
import { useRemember } from '@inertiajs/react'

export default function Profile() {
    const [formState, setFormState] = useRemember({
        first_name: null,
        last_name: null,
        // ...
    })

    // ...
}
```

```js Svelte icon="s"
import { remember } from '@inertiajs/svelte'

let form = remember({
    first_name: null,
    last_name: null,
})

// ...
```

</CodeGroup>

Now, whenever your local `form` state changes, Inertia will automatically save this data to the history state and will also restore it on history navigation.

## Multiple Components

If your page contains multiple components that use the remember functionality provided by Inertia, you need to provide a unique key for each component so that Inertia knows which data to restore to each component.

<CodeGroup>

```js Vue 2 icon="vuejs"
{
    remember: {
        data: ['form'],
        key: 'Users/Create',
    },
    data() {
        return {
            form: {
                first_name: null,
                last_name: null,
            },
        }
    },
}
```

```js Vue 3 icon="vuejs"
import { useRemember } from '@inertiajs/vue3'

const form = useRemember({
    first_name: null,
    last_name: null,
}, 'Users/Create')
```

```jsx React icon="react"
import { useRemember } from '@inertiajs/react'

export default function Profile() {
    const [formState, setFormState] = useRemember({
        first_name: null,
        last_name: null,
    }, 'Users/Create')

}
```

```js Svelte icon="s"
import { page, remember } from '@inertiajs/svelte'

let form = remember({
    first_name: null,
    last_name: null,
}, 'Users/Create')
```

</CodeGroup>

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.

<CodeGroup>

```js Vue 2 icon="vuejs"
{
    remember: {
        data: ['form'],
        key() {
            return `Users/Edit:${this.user.id}`
        }
    },
    data() {
        return {
            form: {
                first_name: this.user.first_name,
                last_name: this.user.last_name,
            },
        }
    },
}
```

```js Vue 3 icon="vuejs"
import { useRemember } from '@inertiajs/vue3'

const props = defineProps({ user: Object })

const form = useRemember({
    first_name: null,
    last_name: null,
}, `Users/Edit:${props.user.id}`)
```

```jsx React icon="react"
import { useRemember } from '@inertiajs/react'

export default function Profile() {
    const [formState, setFormState] = useRemember({
        first_name: props.user.first_name,
        last_name: props.user.last_name,
    }, `Users/Edit:${this.user.id}`)
}
```

```js Svelte icon="s"
import { page, remember } from '@inertiajs/svelte'

let form = remember({
    first_name: $page.props.user.first_name,
    last_name: $page.props.user.last_name,
}, `Users/Edit:${$page.props.user.id}`)
```

</CodeGroup>

## Form Helper

If you're using the [Inertia form helper](/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.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { useForm } from '@inertiajs/vue2'

form: useForm('CreateUser', data)
form: useForm(`EditUser:${this.user.id}\
```

```js Vue 3 icon="vuejs"
import { useForm } from '@inertiajs/vue3'

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

```js React icon="react"
import { useForm } from '@inertiajs/react'

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

```js Svelte icon="s"
import { useForm } from '@inertiajs/svelte'

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

</CodeGroup>

## Manually Saving State

The `remember` property in Vue 2, and the `useRemember` hook in Vue 3, React, and Svelte all watch for data changes and automatically save those changes to the history state. Then, Inertia will restore the data on page load.

However, it's also possible to manage this manually using the underlying `remember()` and `restore()` methods in Inertia.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

// Save local component state to history state...
router.remember(data, 'my-key')

// Restore local component state from history state...
let data = router.restore('my-key')
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

// Save local component state to history state...
router.remember(data, 'my-key')

// Restore local component state from history state...
let data = router.restore('my-key')
```

```js React icon="react"
import { router } from '@inertiajs/react'

// Save local component state to history state...
router.remember(data, 'my-key')

// Restore local component state from history state...
let data = router.restore('my-key')
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

// Save local component state to history state...
router.remember(data, 'my-key')

// Restore local component state from history state...
let data = router.restore('my-key')
```

</CodeGroup>

---

## File: v1/advanced/scroll-management.mdx

---
title: Scroll Management
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Scroll Resetting

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.

In addition, Inertia keeps track of the scroll position of each page and automatically restores that scroll position as you navigate forward and back in history.

## Scroll Preservation

Sometimes it's desirable to prevent the default scroll resetting when making visits. You can disable this behavior by setting the `preserveScroll` option to `false`.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.visit(url, { preserveScroll: false })
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.visit(url, { preserveScroll: false })
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.visit(url, { preserveScroll: false })
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.visit(url, { preserveScroll: false })
```

</CodeGroup>

If you'd like to only preserve the scroll position if the response includes validation errors, set the `preserveScroll` option to "errors".

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.visit(url, { preserveScroll: 'errors' })
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.visit(url, { preserveScroll: 'errors' })
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.visit(url, { preserveScroll: 'errors' })
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.visit(url, { preserveScroll: 'errors' })
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

</CodeGroup>

When using an [Inertia link](/v1/the-basics/links), you can preserve the scroll position using the `preserveScroll` prop.

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

<a preserveScroll href="/">Home</a>
```

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/" use:inertia="{{ preserveScroll: true }}">Home</a>

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

</CodeGroup>

## Scroll Regions

If your app doesn't use document body scrolling, but instead has scrollable elements (using the `overflow` CSS property), scroll resetting will not work.

In these situations, you must tell Inertia which scrollable elements to manage by adding the `scroll-region` attribute to the element.

```html
<div class="overflow-y-auto" scroll-region>
    <!-- Your page content -->
</div>
```

---

## File: v1/advanced/server-side-rendering.mdx

---
title: Server-Side Rendering (SSR)
---

import { ClientSpecific } from "/snippets/client-specific.jsx"
import { ReactSpecific } from "/snippets/react-specific.jsx"
import { SvelteSpecific } from "/snippets/svelte-specific.jsx"
import { VueSpecific } from "/snippets/vue-specific.jsx"
import { Vue2Specific } from "/snippets/vue2-specific.jsx"
import { Vue3Specific } from "/snippets/vue3-specific.jsx"

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

Server-side rendering pre-renders your JavaScript pages on the server, allowing your visitors to receive fully rendered HTML when they visit your application. Since fully rendered HTML is served by your application, it's also easier for search engines to index your site.

Server-side rendering uses Node.js to render your pages in a background process; therefore, Node must be available on your server for server-side rendering to function properly.

## Laravel Starter Kits

If you are using [Laravel Breeze or Jetstream](https://laravel.com/docs/starter-kits), you may install the starter kit's scaffolding with Inertia SSR support pre-configured using the `--ssr` flag.

```bash
php artisan breeze:install react --ssr
php artisan breeze:install vue --ssr
```

## Install Dependencies

If you are not using a Laravel starter kit and would like to manually configure SSR, we'll first install the additional dependencies required for server-side rendering. This is only necessary for the Vue adapters, so you can skip this step if you're using React or Svelte.

<CodeGroup>

```bash Vue 2
npm install vue-server-renderer
```

```bash Vue 3
npm install @vue/server-renderer
```

```js React icon="react"
// No additional dependencies required
```

```js Svelte icon="s"
// No additional dependencies required
```

</CodeGroup>

Then, make sure you have the latest version of the Inertia Laravel adapter installed.

```bash
composer require inertiajs/inertia-laravel
```

## Add Server Entry-Point

Next, we'll create a `resources/js/ssr.js` file within our Laravel project that will serve as our SSR entry point.

```bash
touch resources/js/ssr.js
```

This file is going to look very similar to your `resources/js/app.js` file, except it's not going to run in the browser, but rather in Node.js. Here's a complete example.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { createInertiaApp } from '@inertiajs/vue2'
import createServer from '@inertiajs/vue2/server'
import Vue from 'vue'
import { createRenderer } from 'vue-server-renderer'

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

```js Vue 3 icon="vuejs"
import { createInertiaApp } from '@inertiajs/vue3'
import createServer from '@inertiajs/vue3/server'
import { renderToString } from '@vue/server-renderer'
import { createSSRApp, h } from 'vue'

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

```jsx React icon="react"
import { createInertiaApp } from '@inertiajs/react'
import createServer from '@inertiajs/react/server'
import ReactDOMServer from 'react-dom/server'

createServer(page =>
    createInertiaApp({
        page,
        render: ReactDOMServer.renderToString,
        resolve: name => {
            const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
            return pages[`./Pages/${name}.jsx`]
        },
        setup: ({ App, props }) => <App {...props} />,
    }),
)
```

```js Svelte icon="s"
import { createInertiaApp } from '@inertiajs/svelte'
import createServer from '@inertiajs/svelte/server'

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

</CodeGroup>

When creating this file, be sure to add anything that's missing from your `app.js` file that makes sense to run in SSR mode, such as plugins or custom mixins.

## Setup Vite

Next, we need to update our Vite configuration to build our new `ssr.js` file. We can do this by adding a `ssr` property to Laravel's Vite plugin configuration in our `vite.config.js`file.

```js
export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            ssr: 'resources/js/ssr.js', // [!code ++]
            refresh: true,
        }),
        // ...
    ],
})
```

## Update Npm Script

Next, let's update the `build` script in our `package.json` file to also build our new `ssr.js` file.

```json
"scripts": {
    "dev": "vite",
    "build": "vite build" // [!code --]
    "build": "vite build && vite build --ssr" // [!code ++]
},
```

Now you can build both your client-side and server-side bundles.

```bash
npm run build
```

## Running the SSR Server

Now that you have built both your client-side and server-side bundles, you should be able run the Node-based Inertia SSR server using the following command.

```bash
php artisan inertia:start-ssr
```

With the server running, you should be able to access your app within the browser with server-side rendering enabled. In fact, you should be able to disable JavaScript entirely and still navigate around your application.

## Client Side Hydration

<ClientSpecific>
Since your website is now being server-side rendered, you can instruct <VueSpecific>Vue</VueSpecific><ReactSpecific>React</ReactSpecific><SvelteSpecific>Svelte</SvelteSpecific> to "hydrate" the static markup and make it interactive instead of re-rendering all the HTML that we just generated.
</ClientSpecific>

<Vue2Specific>Inertia automatically enables client-side hydration in Vue 2 apps, so no changes are required.</Vue2Specific>

<Vue3Specific>To enable client-side hydration in a Vue 3 app, update your `app.js` file to use `createSSRApp` instead of `createApp`:</Vue3Specific>

<ReactSpecific>To enable client-side hydration in a React app, update your `app.js` file to use `hydrateRoot` instead of `createRoot`:</ReactSpecific>

<SvelteSpecific>To enable client-side hydration in a Svelte app, set the `hydratable` compiler option to `true` in your `vite.config.js` file:</SvelteSpecific>

<CodeGroup>

```js Vue 2 icon="vuejs"
// No changes required
```

```js Vue 3
import { createApp, h } from 'vue' // [!code --]
import { createSSRApp, h } from 'vue' // [!code ++]
import { createInertiaApp } from '@inertiajs/vue3'

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

```js React icon="react"
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client' // [!code --]
import { hydrateRoot } from 'react-dom/client' // [!code ++]

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
        return pages[`./Pages/${name}.jsx`]
    },
    setup({ el, App, props }) {
        createRoot(el).render(<App {...props} />) // [!code --]
        hydrateRoot(el, <App {...props} />) // [!code ++]
    },
})
```

```js Svelte icon="s"
import { svelte } from '@sveltejs/vite-plugin-svelte'
import laravel from 'laravel-vite-plugin'
import { defineConfig } from 'vite'

export default defineConfig({
    plugins: [
        laravel.default({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            ssr: 'resources/js/ssr.js',
            refresh: true,
        }),
        svelte(), // [!code --]
        svelte({ // [!code ++:5]
            compilerOptions: {
                hydratable: true,
            },
        }),
    ],
})
```

</CodeGroup>

<SvelteSpecific>

You'll also need to enable hydration in your `app.js` file:

```js
import { createInertiaApp } from '@inertiajs/svelte'

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
        return pages[`./Pages/${name}.svelte`]
    },
    setup({ el, App, props }) { // [!code --:3]
        new App({ target: el, props })
    },
    setup({ el, App }) { // [!code ++:3]
        new App({ target: el, hydrate: true })
    },
})
```

</SvelteSpecific>

## Deployment

When deploying your SSR enabled app to production, you'll need to build both the client-side (`app.js`) and server-side bundles (`ssr.js`), and then run the SSR server as a background process, typically using a process monitoring tool such as Supervisor.

```bash
php artisan inertia:start-ssr
```

To stop the SSR server, for instance when you deploy a new version of your website, you may utilize the `inertia:stop-ssr` Artisan command. Your process monitor (such as Supervisor) should be responsible for automatically restarting the SSR server after it has stopped.

```bash
php artisan inertia:stop-ssr
```

## Laravel Forge

To run the SSR server on Forge, you should create a new daemon that runs `php artisan inertia:start-ssr` from the root of your app. Or, you may utilize the built-in Inertia integration from your Forge application's management dashboard.

Next, whenever you deploy your application, you can automatically restart the SSR server by calling the `php artisan inertia:stop-ssr` command. This will stop the existing SSR server, forcing a new one to be started by your process monitor.

## Heroku

To run the SSR server on Heroku, update the `web` configuration in your `Procfile` to run the SSR server before starting your web server.

```bash
web: php artisan inertia:start-ssr & vendor/bin/heroku-php-apache2 public/
```

Note, you must have the `heroku/nodejs` buildpack installed in addition to the `heroku/php` buildback for the SSR server to run.

---

## File: v1/advanced/testing.mdx

---
title: Testing
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

## End-to-end Tests

One popular approach to testing your JavaScript page components is to use an end-to-end testing tool like [Cypress](https://www.cypress.io/) or [Laravel Dusk](https://laravel.com/docs/dusk). These are browser automation tools that allow you to run real simulations of your app in the browser. These tests are known to be slower; however, since they test your application at the same layer as your end users, they can provide a lot of confidence that your app is working correctly. And, since these tests are run in the browser, your JavaScript code is actually executed and tested as well.

## Client-side Unit Tests

Another approach to testing your page components is using a client-side unit testing framework, such as [Jest](https://jestjs.io/) or [Mocha](https://mochajs.org/). This approach allows you to test your JavaScript page components in isolation using Node.js.

## Endpoint Tests

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

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

```php
use Inertia\Testing\AssertableInertia as Assert;
class PodcastsControllerTest extends TestCase
{
public function test_can_view_podcast()
{
$this->get('/podcasts/41')
->assertInertia(fn (Assert $page) => $page
->component('Podcasts/Show')
->has('podcast', fn (Assert $page) => $page
->where('id', $podcast->id)
->where('subject', 'The Laravel Podcast')
->where('description', 'The Laravel Podcast brings you Laravel and PHP development news and discussion.')
->has('seasons', 4)
->has('seasons.4.episodes', 21)
->has('host', fn (Assert $page) => $page
->where('id', 1)
->where('name', 'Matt Stauffer')
)
->has('subscribers', 7, fn (Assert $page) => $page
->where('id', 2)
->where('name', 'Claudio Dekker')
->where('platform', 'Apple Podcasts')
->etc()
->missing('email')
->missing('password')
)
)
);
}
}
```

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

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

```php
$response->assertInertia(fn (Assert $page) => $page
// Checking a root-level property...
->has('podcast')
// Checking nested properties using "dot" notation...
->has('podcast.id')
);
```

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

```php
$response->assertInertia(fn (Assert $page) => $page
// Checking if a root-level property has 7 items...
->has('podcasts', 7)
// Checking nested properties using "dot" notation...
->has('podcast.subscribers', 7)
);
```

The `has` method may also be used to scope properties in order to lessen repetition when asserting against nested properties.

```php
$response->assertInertia(fn (Assert $page) => $page
// Creating a single-level property scope...
->has('message', fn (Assert $page) => $page
// We can now continue chaining methods...
->has('subject')
->has('comments', 5)
// And can even create a deeper scope using "dot" notation...
->has('comments.0', fn (Assert $page) => $page
->has('body')
->has('files', 1)
->has('files.0', fn (Assert $page) => $page
->has('url')
)
)
)
);
```

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

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

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

```php
$response->assertInertia(fn (Assert $page) => $page
->has('message', fn (Assert $page) => $page
// Assert that the subject prop matches the given message...
->where('subject', 'This is an example message')
// Or, assert against deeply nested values...
->where('comments.0.files.0.name', 'example-attachment.pdf')
)
);
```

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

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

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

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

---

## File: v1/core-concepts/how-it-works.mdx

---
title: How It Works
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

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

At its core, Inertia is essentially a client-side routing library. It allows you to make page visits without forcing a full page reload. This is done using the `<Link>` component, a light-weight wrapper around a normal anchor link. When you click an Inertia link, Inertia intercepts the click and makes the visit via XHR instead. You can even make these visits programmatically in JavaScript using `router.visit()`.

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

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

To learn more about the nitty-gritty, technical details of how Inertia works under the hood, check out the [protocol page](/v1/core-concepts/the-protocol).

---

## File: v1/core-concepts/the-protocol.mdx

---
title: The Protocol
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

This page contains a detailed specification of the Inertia protocol. Be sure to read the [how it works](/v1/core-concepts/how-it-works) page first for a high-level overview.

## HTML Responses

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

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

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

RESPONSE
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

<html>
    <head>
        <title>My app</title>
        <link href="/css/app.css" rel="stylesheet">
        <script src="/js/app.js" defer></script>
    </head>
    <body>
        <div id="app" data-page='{"component":"Event","props":{"event":{"id":80,"title":"Birthday party","start_date":"2019-06-02","description":"Come out and celebrate Jonathan&apos;s 36th birthday party!"}},"url":"/events/80","version":"c32b8e4965f418ad16eaebba1d4e960f"}'></div>
    </body>
</html>
```


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


## Inertia responses

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

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


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

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

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

## The page object

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

- **component:** The name of the JavaScript page component.
- **props:** The page props (data).
- **url:** The page URL.
- **version:** The current asset version.

On standard full page visits, the page object is JSON encoded into the `data-page` attribute in the
root ``. On Inertia visits, the page object is returned as the JSON payload.

## Asset versioning


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


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


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


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


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


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

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

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

## Partial reloads

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

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

The `X-Inertia-Partial-Data` header is a comma separated list of the desired props (data) keys that
should be returned.

The `X-Inertia-Partial-Component` header includes the name of the component that is being partially
reloaded. This is necessary, since partial reloads only work for requests made to the same page component. If
the final destination is different for some reason (eg. the user was logged out and is now on the login page),
then no partial reloading will occur.


```http
REQUEST
GET: http://example.com/events
Accept: text/html, application/xhtml+xml
X-Requested-With: XMLHttpRequest
X-Inertia: true
X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5
X-Inertia-Partial-Data: events
X-Inertia-Partial-Component: Events

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

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

---

## File: v1/core-concepts/who-is-it-for.mdx

---
title: Who Is Inertia.js For?
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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.

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

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

**Inertia empowers you to build a modern, JavaScript-based single-page application without the tiresome complexity.**

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

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.

---

## File: v1/getting-started/demo-application.mdx

---
title: Demo Application
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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).

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

[](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).

## Third Party

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

- [Ruby on Rails/Vue](https://github.com/ledermann/pingcrm/) by Georg Ledermann
- [Laravel/React](https://github.com/Landish/pingcrm-react) by Lado Lomidze
- [Laravel/Svelte](https://github.com/zgabievi/pingcrm-svelte) by Zura Gabievi
- [Laravel/Mithril.js](https://github.com/tbreuss/pingcrm-mithril) by Thomas Breuss
- [Yii 2/Vue](https://github.com/tbreuss/pingcrm-yii2) by Thomas Breuss
- [Symfony/Vue](https://github.com/aleksblendwerk/pingcrm-symfony) by Aleks Seltenreich
- [Clojure/React](https://github.com/prestancedesign/pingcrm-clojure) by Michaël Salihi

---

## File: v1/getting-started/index.mdx

---
title: Introduction
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

Inertia is a new approach to building classic server-driven web apps. We call it the modern monolith.

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.

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).

## Not a Framework

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).

## Next Steps

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).

---

## File: v1/getting-started/upgrade-guide.mdx

---
title: Upgrade Guide for v1.0
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

You can find the legacy docs for Inertia.js v0.11 at [legacy.inertiajs.com](https://legacy.inertiajs.com).

## What's New

Inertia.js v1.0 focuses on simplifying the overall architecture of the project with the goal of making Inertia easier to maintain and easier to use.

It includes a number of breaking changes, mostly related to package names and updated named exports. This guide explains how to upgrade your project to v1.0.

For a complete list of all the changes, see the [release notes](https://github.com/inertiajs/inertia/releases/tag/v1.0.0).

## New Dependencies

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

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

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

<CodeGroup>

```bash Vue 2
npm remove @inertiajs/inertia @inertiajs/inertia-vue @inertiajs/progress @inertiajs/server
```

```bash Vue 3
npm remove @inertiajs/inertia @inertiajs/inertia-vue3 @inertiajs/progress @inertiajs/server
```

```bash React icon="react"
npm remove @inertiajs/inertia @inertiajs/inertia-react @inertiajs/progress @inertiajs/server
```

```bash Svelte icon="s"
npm remove @inertiajs/inertia @inertiajs/inertia-svelte @inertiajs/progress @inertiajs/server
```

</CodeGroup>

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

<CodeGroup>

```bash Vue 2
npm install @inertiajs/vue2
```

```bash Vue 3
npm install @inertiajs/vue3
```

```bash React icon="react"
npm install @inertiajs/react
```

```bash Svelte icon="s"
npm install @inertiajs/svelte
```

</CodeGroup>

## Renamed Imports

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

Additionally, some exports have been renamed and previously deprecated exports have been removed. For example, the `Inertia` export has been renamed to `router`.

Here is a complete list of all the import changes:

<CodeGroup>

```js Vue 2
import { Inertia } from '@inertiajs/inertia' // [!code --]
import { router } from '@inertiajs/vue2' // [!code ++]

import createServer from '@inertiajs/server' // [!code --]
import createServer from '@inertiajs/vue2/server' // [!code ++]

import { createInertiaApp } from '@inertiajs/inertia-vue' // [!code --:5]
import { App } from '@inertiajs/inertia-vue'
import { app } from '@inertiajs/inertia-vue'
import { InertiaApp } from '@inertiajs/inertia-vue'
import { plugin } from '@inertiajs/inertia-vue'
import { createInertiaApp } from '@inertiajs/vue2' // [!code ++]

import { Head } from '@inertiajs/inertia-vue' // [!code --:2]
import { InertiaHead } from '@inertiajs/inertia-vue'
import { Head } from '@inertiajs/vue2' // [!code ++]

import { Link } from '@inertiajs/inertia-vue' // [!code --:3]
import { link } from '@inertiajs/inertia-vue'
import { InertiaLink } from '@inertiajs/inertia-vue'
import { Link } from '@inertiajs/vue2' // [!code ++]
```

```js Vue 3
import { Inertia } from '@inertiajs/inertia' // [!code --]
import { router } from '@inertiajs/vue3' // [!code ++]

import createServer from '@inertiajs/server' // [!code --]
import createServer from '@inertiajs/vue3/server' // [!code ++]

import { createInertiaApp } from '@inertiajs/inertia-vue3' // [!code --:5]
import { App } from '@inertiajs/inertia-vue3'
import { app } from '@inertiajs/inertia-vue3'
import { plugin } from '@inertiajs/inertia-vue3'
import { InertiaApp } from '@inertiajs/inertia-vue3'
import { createInertiaApp } from '@inertiajs/vue3' // [!code ++]

import { usePage } from '@inertiajs/inertia-vue3' // [!code --]
import { usePage } from '@inertiajs/vue3' // [!code ++]

import { useForm } from '@inertiajs/inertia-vue3' // [!code --]
import { useForm } from '@inertiajs/vue3' // [!code ++]

import { useRemember } from '@inertiajs/inertia-vue3' // [!code --]
import { useRemember } from '@inertiajs/vue3' // [!code ++]

import { Head } from '@inertiajs/inertia-vue3' // [!code --:2]
import { InertiaHead } from '@inertiajs/inertia-vue3'
import { Head } from '@inertiajs/vue3' // [!code ++]

import { Link } from '@inertiajs/inertia-vue3' // [!code --:3]
import { link } from '@inertiajs/inertia-vue3'
import { InertiaLink } from '@inertiajs/inertia-vue3'
import { Link } from '@inertiajs/vue3' // [!code ++]
```

```js React icon="react"
import { Inertia } from '@inertiajs/inertia' // [!code --]
import { router } from '@inertiajs/react' // [!code ++]

import createServer from '@inertiajs/server' // [!code --]
import createServer from '@inertiajs/react/server' // [!code ++]

import { createInertiaApp } from '@inertiajs/inertia-react' // [!code --:4]
import { App } from '@inertiajs/inertia-react'
import { app } from '@inertiajs/inertia-react'
import { InertiaApp } from '@inertiajs/inertia-react'
import { createInertiaApp } from '@inertiajs/react' // [!code ++]

import { usePage } from '@inertiajs/inertia-react' // [!code --]
import { usePage } from '@inertiajs/react' // [!code ++]

import { useForm } from '@inertiajs/inertia-react' // [!code --]
import { useForm } from '@inertiajs/react' // [!code ++]

import { useRemember } from '@inertiajs/inertia-react' // [!code --:2]
import { useRememberedState } from '@inertiajs/inertia-react'
import { useRemember } from '@inertiajs/react' // [!code ++]

import { Head } from '@inertiajs/inertia-react' // [!code --:2]
import { InertiaHead } from '@inertiajs/inertia-react'
import { Head } from '@inertiajs/react' // [!code ++]

import { Link } from '@inertiajs/inertia-react' // [!code --:3]
import { link } from '@inertiajs/inertia-react'
import { InertiaLink } from '@inertiajs/inertia-react'
import { Link } from '@inertiajs/react' // [!code ++]
```

```js Svelte icon="s"
import { Inertia } from '@inertiajs/inertia' // [!code --]
import { router } from '@inertiajs/svelte' // [!code ++]

import { createInertiaApp } from '@inertiajs/inertia-svelte' // [!code --:4]
import { App } from '@inertiajs/inertia-svelte'
import { app } from '@inertiajs/inertia-svelte'
import { InertiaApp } from '@inertiajs/inertia-svelte'
import { createInertiaApp } from '@inertiajs/svelte' // [!code ++]

import { page } from '@inertiajs/inertia-svelte' // [!code --]
import { page } from '@inertiajs/svelte' // [!code ++]

import { inertia } from '@inertiajs/inertia-svelte' // [!code --]
import { inertia } from '@inertiajs/svelte' // [!code ++]

import { useForm } from '@inertiajs/inertia-svelte' // [!code --]
import { useForm } from '@inertiajs/svelte' // [!code ++]

import { useRemember } from '@inertiajs/inertia-svelte' // [!code --:2]
import { remember } from '@inertiajs/inertia-svelte'
import { remember } from '@inertiajs/svelte' // [!code ++]

import { Link } from '@inertiajs/inertia-svelte' // [!code --:3]
import { link } from '@inertiajs/inertia-svelte'
import { InertiaLink } from '@inertiajs/inertia-svelte'
import { Link } from '@inertiajs/svelte' // [!code ++]
```

</CodeGroup>

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

## Progress

Previously, the progress indicator was available as a separate plugin (`@inertiajs/progress`). It is now installed and enabled by default.

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

<CodeGroup>

```bash Vue 2
npm remove @inertiajs/progress
```

```bash Vue 3
npm remove @inertiajs/progress
```

```bash React icon="react"
npm remove @inertiajs/progress
```

```bash Svelte icon="s"
npm remove @inertiajs/progress
```

</CodeGroup>

Next, remove the `InertiaProgress` import and `InertiaProgress.init()` call, as they are no longer required.

```js
import { InertiaProgress } from '@inertiajs/progress' // [!code --:2]
InertiaProgress.init()
```

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

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

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

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

## Setup Arguments

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

```js
createInertiaApp({
    // ...
    setup({ app, props }) { // [!code --]
    setup({ App, props }) { // [!code ++]
        // ...
    },
})
```

## Simplified Usepage

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

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

```js
import { computed } from 'vue'
const appName = computed(() => usePage().props.value.appName) // [!code --]
const appName = computed(() => usePage().props.appName) // [!code ++]
```

---

## File: v1/installation/client-side-setup.mdx

---
title: Client-side Setup
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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.

## Laravel Starter Kits

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.

## Install Dependencies

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

<CodeGroup>

```bash Vue 2
npm install @inertiajs/vue2
```

```bash Vue 3
npm install @inertiajs/vue3
```

```bash React icon="react"
npm install @inertiajs/react
```

```bash Svelte icon="s"
npm install @inertiajs/svelte
```

</CodeGroup>

## Initialize the Inertia App

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import Vue from 'vue'
import { createInertiaApp } from '@inertiajs/vue2'

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

        new Vue({
            render: h => h(App, props),
        }).$mount(el)
    },
})
```

```js Vue 3 icon="vuejs"
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
        return pages[`./Pages/${name}.jsx`]
    },
    setup({ el, App, props }) {
        createRoot(el).render(<App {...props} />)
    },
})
```

```js Svelte icon="s"
import { createInertiaApp } from '@inertiajs/svelte'

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
        return pages[`./Pages/${name}.svelte`]
    },
    setup({ el, App, props }) {
        new App({ target: el, props })
    },
})
```

</CodeGroup>

The `setup` callback receives everything necessary to initialize the client-side framework, including the root Inertia `App` component.

## Resolving Components

The `resolve` callback tells Inertia how to load a page component. It receives a page name (string), and returns a page component module. How you implement this callback depends on which bundler (Vite or Webpack) you're using.

<CodeGroup>

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

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

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

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

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

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

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

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

</CodeGroup>

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.

## Defining a Root Element

By default, Inertia assumes that your application's root template has a root element with an `id` of `app`. If your application's root element has a different `id`, you can provide it using the `id` property.

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

---

## File: v1/installation/server-side-setup.mdx

---
title: Server-side Setup
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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).

Inertia is fine-tuned for Laravel, so the documentation examples on this website utilize Laravel. For examples of using Inertia with other server-side frameworks, please refer to the framework specific documentation maintained by that adapter.

## Laravel Starter Kits

Laravel's [starter kits](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.

## Install Dependencies

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

```bash
composer require inertiajs/inertia-laravel
```

## Root Template

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

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

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

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

## Middleware

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

```sh
php artisan inertia:middleware
```

Once the middleware has been published, append the `HandleInertiaRequests` middleware to the `web` middleware group in your application's `bootstrap/app.php` file.

```php
use App\Http\Middleware\HandleInertiaRequests;

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        HandleInertiaRequests::class,
    ]);
})
```

This middleware provides a `version()` method for setting your [asset version](/v1/advanced/asset-versioning), as well as a `share()` method for defining [shared data](/v1/the-basics/shared-data).

## Creating Responses

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).

```php
use Inertia\Inertia;

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

---

## File: v1/the-basics/file-uploads.mdx

---
title: File Uploads
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Formdata Conversion

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

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

You can learn more about the `FormData` interface via its [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/FormData).

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

## File Upload Example

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

<CodeGroup>

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

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

export default {
    data() {
        return {
            form: useForm({
                name: null,
                avatar: null,
            }),
        }
    },
    methods: {
        submit() {
            this.form.post('/users')
        },
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
    name: null,
    avatar: null,
})

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

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

```jsx React icon="react"
import { useForm } from '@inertiajs/react'

const { data, setData, post, progress } = useForm({
    name: null,
    avatar: null,
})

function submit(e) {
    e.preventDefault()
    post('/users')
}

return (
    <form onSubmit={submit}>
        <input type="text" value={data.name} onChange={e => setData('name', e.target.value)} />
        <input type="file" value={data.avatar} onChange={e => setData('avatar', e.target.files[0])} />
        {progress && (
            <progress value={progress.percentage} max="100">
                {progress.percentage}%
            </progress>
        )}
        <button type="submit">Submit</button>
    </form>
)
```

```html Svelte icon="s"
<script>
import { useForm } from '@inertiajs/svelte'

let form = useForm({
    name: null,
    avatar: null,
})

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

<form on:submit|preventDefault={submit}>
    <input type="text" bind:value={$form.name} />
    <input type="file" on:input={e => $form.avatar = e.target.files[0]} />
    {#if $form.progress}
        <progress value={$form.progress.percentage} max="100">
            {$form.progress.percentage}%
        </progress>
    {/if}
    <button type="submit">Submit</button>
</form>
```

</CodeGroup>

This example uses the [Inertia form helper](/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](/v1/the-basics/manual-visits) as well.

## Multipart Limitations

Uploading files using a `multipart/form-data` request is not natively supported in some server-side frameworks when using the `PUT`,`PATCH`, or `DELETE` HTTP methods. The simplest workaround for this limitation is to simply upload files using a `POST` request instead.

However, some frameworks, such as [Laravel](https://laravel.com/docs/8.x/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.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post(`/users/${user.id}\
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.post(`/users/${user.id}\
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.post(`/users/${user.id}\
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.post(`/users/${user.id}\
```

</CodeGroup>

---

## File: v1/the-basics/forms.mdx

---
title: Forms
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Submitting Forms

While it's possible to make classic HTML form submissions with Inertia, it's not recommended since they cause full-page reloads. Instead, it's better to intercept form submissions and then make the [request using Inertia](/v1/the-basics/manual-visits).

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <form @submit.prevent="submit">
        <label for="first_name">First name:</label>
        <input id="first_name" v-model="form.first_name" />
        <label for="last_name">Last name:</label>
        <input id="last_name" v-model="form.last_name" />
        <label for="email">Email:</label>
        <input id="email" v-model="form.email" />
        <button type="submit">Submit</button>
    </form>
</template>

<script>
import { router } from '@inertiajs/vue2'

export default {
    data() {
        return {
            form: {
                first_name: null,
                last_name: null,
                email: null,
            },
        }
    },
    methods: {
        submit() {
            router.post('/users', this.form)
        },
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { reactive } from 'vue'
import { router } from '@inertiajs/vue3'

const form = reactive({
    first_name: null,
    last_name: null,
    email: null,
})

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

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

```jsx React icon="react"
import { useState } from 'react'
import { router } from '@inertiajs/react'

export default function Edit() {
    const [values, setValues] = useState({
        first_name: "",
        last_name: "",
        email: "",
    })

    function handleChange(e) {
        const key = e.target.id;
        const value = e.target.value
        setValues(values => ({
                ...values,
                [key]: value,
        }))
    }

    function handleSubmit(e) {
        e.preventDefault()
        router.post('/users', values)
    }

    return (
        <form onSubmit={handleSubmit}>
            <label htmlFor="first_name">First name:</label>
            <input id="first_name" value={values.first_name} onChange={handleChange} />
            <label htmlFor="last_name">Last name:</label>
            <input id="last_name" value={values.last_name} onChange={handleChange} />
            <label htmlFor="email">Email:</label>
            <input id="email" value={values.email} onChange={handleChange} />
            <button type="submit">Submit</button>
        </form>
    )
}
```

```html Svelte icon="s"
<script>
    import { router } from '@inertiajs/svelte'

    let values = {
        first_name: null,
        last_name: null,
        email: null,
    }

    function handleSubmit() {
        router.post('/users', values)
    }
</script>

<form on:submit|preventDefault={handleSubmit}>
    <label for="first_name">First name:</label>
    <input id="first_name" bind:value={values.first_name}>

    <label for="last_name">Last name:</label>
    <input id="last_name" bind:value={values.last_name}>

    <label for="email">Email:</label>
    <input id="email" bind:value={values.email}>

    <button type="submit">Submit</button>
</form>
```

</CodeGroup>

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

Instead, your server-side route / controller typically issues a [redirect](/v1/the-basics/redirects) response. And, Of course, there is nothing stopping you from redirecting the user right back to the page they were previously on. Using this approach, handling Inertia form submissions feels very similar to handling classic HTML form submissions.

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

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

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

## Server-side Validation

Handling server-side validation errors in Inertia works a little different than handling errors from manual XHR / fetch requests. When making XHR / fetch requests, you typically inspect the response for a `422`status code and manually update the form's error state.

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

For a full discussion on handling and displaying validation errors with Inertia, please consult the [validation](/v1/the-basics/validation) documentation.

## Form Helper

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <form @submit.prevent="form.post('/login')">
        <!-- email -->
        <input type="text" v-model="form.email">
        <div v-if="form.errors.email">{{ form.errors.email }}</div>
        <!-- password -->
        <input type="password" v-model="form.password">
        <div v-if="form.errors.password">{{ form.errors.password }}</div>
        <!-- remember me -->
        <input type="checkbox" v-model="form.remember"> Remember Me
        <!-- submit -->
        <button type="submit" :disabled="form.processing">Login</button>
    </form>
</template>

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

export default {
    data() {
        return {
            form: useForm({
                email: null,
                password: null,
                remember: false,
            }),
        }
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
    email: null,
    password: null,
    remember: false,
})
</script>

<template>
    <form @submit.prevent="form.post('/login')">
        <!-- email -->
        <input type="text" v-model="form.email">
        <div v-if="form.errors.email">{{ form.errors.email }}</div>
        <!-- password -->
        <input type="password" v-model="form.password">
        <div v-if="form.errors.password">{{ form.errors.password }}</div>
        <!-- remember me -->
        <input type="checkbox" v-model="form.remember"> Remember Me
        <!-- submit -->
        <button type="submit" :disabled="form.processing">Login</button>
    </form>
</template>
```

```jsx React icon="react"
import { useForm } from '@inertiajs/react'

const { data, setData, post, processing, errors } = useForm({
    email: '',
    password: '',
    remember: false,
})

function submit(e) {
    e.preventDefault()
    post('/login')
}

return (
    <form onSubmit={submit}>
        <input type="text" value={data.email} onChange={e => setData('email', e.target.value)} />
        {errors.email && <div>{errors.email}</div>}
        <input type="password" value={data.password} onChange={e => setData('password', e.target.value)} />
        {errors.password && <div>{errors.password}</div>}
        <input type="checkbox" checked={data.remember} onChange={e => setData('remember', e.target.checked)} /> Remember Me
        <button type="submit" disabled={processing}>Login</button>
    </form>
)
```

```html Svelte icon="s"
<script>
import { useForm } from '@inertiajs/svelte'

let form = useForm({
    email: null,
    password: null,
    remember: false,
})

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

<form on:submit|preventDefault={submit}>
    <input type="text" bind:value={$form.email} />
    {#if $form.errors.email}
        <div class="form-error">{$form.errors.email}</div>
    {/if}
    <input type="password" bind:value={$form.password} />
    {#if $form.errors.password}
        <div class="form-error">{$form.errors.password}</div>
    {/if}
    <input type="checkbox" bind:checked={$form.remember} /> Remember Me
    <button type="submit" disabled={$form.processing}>Submit</button>
</form>
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
form.submit(method, url, options)
form.get(url, options)
form.post(url, options)
form.put(url, options)
form.patch(url, options)
form.delete(url, options)
```

```js Vue 3 icon="vuejs"
form.submit(method, url, options)
form.get(url, options)
form.post(url, options)
form.put(url, options)
form.patch(url, options)
form.delete(url, options)
```

```js React icon="react"
const { submit, get, post, put, patch, delete: destroy } = useForm({ ... })

submit(method, url, options)
get(url, options)
post(url, options)
put(url, options)
patch(url, options)
destroy(url, options)
```

```js Svelte icon="s"
$form.submit(method, url, options)
$form.get(url, options)
$form.post(url, options)
$form.put(url, options)
$form.patch(url, options)
$form.delete(url, options)
```

</CodeGroup>

The submit methods support all of the typical [visit options](/v1/the-basics/manual-visits), such as `preserveState`, `preserveScroll`, and event callbacks, which can be helpful for performing tasks on successful form submissions. For example, you might use the `onSuccess` callback to reset inputs to their original state.

<CodeGroup>

```js Vue 2 icon="vuejs"
form.post('/profile', {
    preserveScroll: true,
    onSuccess: () => form.reset('password'),
})
```

```js Vue 3 icon="vuejs"
form.post('/profile', {
    preserveScroll: true,
    onSuccess: () => form.reset('password'),
})
```

```js React icon="react"
const { post, reset } = useForm({ ... })

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

```js Svelte icon="s"
$form.post('/profile', {
    preserveScroll: true,
    onSuccess: () => $form.reset('password'),
})
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
form
    .transform((data) => ({
        ...data,
        remember: data.remember ? 'on' : '',
    }))
    .post('/login')
```

```js Vue 3 icon="vuejs"
form
    .transform((data) => ({
        ...data,
        remember: data.remember ? 'on' : '',
    }))
    .post('/login')
```

```js React icon="react"
const { transform } = useForm({ ... })

transform((data) => ({
    ...data,
    remember: data.remember ? 'on' : '',
}))
```

```js Svelte icon="s"
$form
    .transform((data) => ({
        ...data,
        remember: data.remember ? 'on' : '',
    }))
    .post('/login')
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<button type="submit" :disabled="form.processing">Submit</button>
```

```vue Vue 3 icon="vuejs"
<button type="submit" :disabled="form.processing">Submit</button>
```

```jsx React icon="react"
const { processing } = useForm({ ... })

<button type="submit" disabled={processing}>Submit</button>
```

```svelte Svelte icon="s"
<button type="submit" disabled={$form.processing}>Submit</button>
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
    {{ form.progress.percentage }}%
</progress>
```

```vue Vue 3 icon="vuejs"
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
    {{ form.progress.percentage }}%
</progress>
```

```jsx React icon="react"
const { progress } = useForm({ ... })

{progress && (
    <progress value={progress.percentage} max="100">
        {progress.percentage}%
    </progress>
)}
```

```svelte Svelte icon="s"
{#if $form.progress}
    <progress value={$form.progress.percentage} max="100">
        {$form.progress.percentage}%
    </progress>
{/if}
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<div v-if="form.errors.email">{{ form.errors.email }}</div>
```

```vue Vue 3 icon="vuejs"
<div v-if="form.errors.email">{{ form.errors.email }}</div>
```

```jsx React icon="react"
const { errors } = useForm({ ... })

{errors.email && <div>{errors.email}</div>}
```

```svelte Svelte icon="s"
{#if $form.errors.email}
    <div>{$form.errors.email}</div>
{/if}
```

</CodeGroup>

For a more thorough discussion of form validation and errors, please consult the [validation documentation](/v1/the-basics/validation).

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

<CodeGroup>

```js Vue 2 icon="vuejs"
// Clear all errors...
form.clearErrors()

// Clear errors for specific fields...
form.clearErrors('field', 'anotherfield')
```

```js Vue 3 icon="vuejs"
// Clear all errors...
form.clearErrors()

// Clear errors for specific fields...
form.clearErrors('field', 'anotherfield')
```

```js React icon="react"
const { clearErrors } = useForm({ ... })

// Clear all errors...
clearErrors()

// Clear errors for specific fields...
clearErrors('field', 'anotherfield')
```

```js Svelte icon="s"
// Clear all errors...
$form.clearErrors()

// Clear errors for specific fields...
$form.clearErrors('field', 'anotherfield')
```

</CodeGroup>

If you're using a client-side input validation libraries or do client-side validation manually, you can set your own errors on the form using the `setErrors()` method.

<CodeGroup>

```js Vue 2 icon="vuejs"
// Set a single error...
form.setError('field', 'Your error message.');

// Set multiple errors at once...
form.setError({
    foo: 'Your error message for the foo field.',
    bar: 'Some other error for the bar field.'
});
```

```js Vue 3 icon="vuejs"
// Set a single error...
form.setError('field', 'Your error message.');

// Set multiple errors at once...
form.setError({
    foo: 'Your error message for the foo field.',
    bar: 'Some other error for the bar field.'
});
```

```js React icon="react"
const { setError } = useForm({ ... })

// Set a single error...
setError('field', 'Your error message.');

// Set multiple errors at once...
setError({
    foo: 'Your error message for the foo field.',
    bar: 'Some other error for the bar field.'
});
```

```js Svelte icon="s"
// Set a single error
$form.setError('field', 'Your error message.');

// Set multiple errors at once
$form.setError({
    foo: 'Your error message for the foo field.',
    bar: 'Some other error for the bar field.'
});
```

</CodeGroup>

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

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

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

<CodeGroup>

```js Vue 2 icon="vuejs"
// Reset the form...
form.reset()

// Reset specific fields...
form.reset('field', 'anotherfield')
```

```js Vue 3 icon="vuejs"
// Reset the form...
form.reset()

// Reset specific fields...
form.reset('field', 'anotherfield')
```

```js React icon="react"
const { reset } = useForm({ ... })

// Reset the form...
reset()

// Reset specific fields...
reset('field', 'anotherfield')
```

```js Svelte icon="s"
// Reset the form...
$form.reset()

// Reset specific fields...
$form.reset('field', 'anotherfield')
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
// Set the form's current values as the new defaults...
form.defaults()

// Update the default value of a single field...
form.defaults('email', 'updated-default@example.com')

// Update the default value of multiple fields...
form.defaults({
    name: 'Updated Example',
    email: 'updated-default@example.com',
})
```

```js Vue 3 icon="vuejs"
// Set the form's current values as the new defaults...
form.defaults()

// Update the default value of a single field...
form.defaults('email', 'updated-default@example.com')

// Update the default value of multiple fields...
form.defaults({
    name: 'Updated Example',
    email: 'updated-default@example.com',
})
```

```js React icon="react"
const { setDefaults } = useForm({ ... })

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

// Update the default value of a single field...
setDefaults('email', 'updated-default@example.com')

// Update the default value of multiple fields...
setDefaults({
    name: 'Updated Example',
    email: 'updated-default@example.com',
})
```

```js Svelte icon="s"
// Set the form's current values as the new defaults...
$form.defaults()

// Update the default value of a single field...
$form.defaults('email', 'updated-default@example.com')

// Change the default value of multiple fields...
$form.defaults({
    name: 'Updated Example',
    email: 'updated-default@example.com',
})
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<div v-if="form.isDirty">There are unsaved form changes.</div>
```

```vue Vue 3 icon="vuejs"
<div v-if="form.isDirty">There are unsaved form changes.</div>
```

```jsx React icon="react"
const { isDirty } = useForm({ ... })

{isDirty && <div>There are unsaved form changes.</div>}
```

```html Svelte icon="s"
{#if $form.isDirty}
    <div>There are unsaved form changes.</div>
{/if}
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
form.cancel()
```

```js Vue 3 icon="vuejs"
form.cancel()
```

```js React icon="react"
const { cancel } = useForm({ ... })

cancel()
```

```js Svelte icon="s"
$form.cancel()
```

</CodeGroup>

To instruct Inertia to store a form's data and errors in [history state](/v1/advanced/remembering-state), you can provide a unique form key as the first argument when instantiating your form.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { useForm } from '@inertiajs/vue2'

form: useForm('CreateUser', data)
form: useForm(`EditUser:${this.user.id}\
```

```js Vue 3 icon="vuejs"
import { useForm } from '@inertiajs/vue3'

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

```js React icon="react"
import { useForm } from '@inertiajs/react'

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

```js Svelte icon="s"
import { useForm } from '@inertiajs/svelte'

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

</CodeGroup>

## File Uploads

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

For a more thorough discussion of file uploads, please consult the [file uploads documentation](/v1/the-basics/file-uploads).

## XHR / Fetch Submissions

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

---

## File: v1/the-basics/links.mdx

---
title: Links
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

## Creating Links

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/" use:inertia>Home</a>

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

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

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

```svelte Svelte icon="s"
import { inertia } from '@inertiajs/svelte'

<button use:inertia="{{ href: '/logout', method: 'post' }}" type="button">Logout</button>

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

</CodeGroup>

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

## Method

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<button use:inertia="{{ href: '/logout', method: 'post' }}" type="button">Logout</button>
```

</CodeGroup>

## Data

When making `POST` or `PUT` requests, you may wish to add additional data to the request. You can accomplish this using the `data` prop. The provided data can be an `object` or `FormData` instance.

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { Link } from '@inertiajs/svelte'

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

</CodeGroup>

## Custom Headers

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<button use:inertia="{{ href: '/endpoint', headers: { foo: bar } }}">Save</button>

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

</CodeGroup>

## Browser History

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

<a replace href="/">Home</a>
```

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/" use:inertia="{{ replace: true }}">Home</a>

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

</CodeGroup>

## State Preservation

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

<input onChange={this.handleChange} value={query} />

<Link href="/search" data={query} preserveState>Search</Link>
```

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<input on:change={handleChange} value={query} />

<button use:inertia="{{ href: '/search', data: query, preserveState: true }}">Search</button>

<Link href="/search" data={query} preserveState>Search</Link>
```

</CodeGroup>

## Scroll Preservation

You can use the `preserveScroll` prop to prevent Inertia from automatically resetting the scroll position when making a page visit.

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

<a preserveScroll href="/">Home</a>
```

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/" use:inertia="{{ preserveScroll: true }}">Home</a>

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

</CodeGroup>

For more information on managing scroll position, please consult the documentation on [scroll management](/v1/advanced/scroll-management).

## Partial Reloads

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

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

```svelte Svelte icon="s"
import { inertia, Link } from '@inertiajs/svelte'

<a href="/users?active=true" use:inertia="{{ only: ['users'] }}">Show active</a>

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

</CodeGroup>

For more information on this topic, please consult the complete documentation on [partial reloads](/v1/advanced/partial-reloads).

## Active States

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Link } from '@inertiajs/vue2'

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

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

// URL starts with (/users, /users/create, /users/1, etc.)...
<Link href="/users" :class="{ 'active': $page.url.startsWith('/users') }">Users</Link>

// Component starts with (Users/Index, Users/Create, Users/Show, etc.)...
<Link href="/users" :class="{ 'active': $page.component.startsWith('Users') }">Users</Link>
```

```vue Vue 3 icon="vuejs"
import { Link } from '@inertiajs/vue3'

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

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

// URL starts with (/users, /users/create, /users/1, etc.)...
<Link href="/users" :class="{ 'active': $page.url.startsWith('/users') }">Users</Link>

// Component starts with (Users/Index, Users/Create, Users/Show, etc.)...
<Link href="/users" :class="{ 'active': $page.component.startsWith('Users') }">Users</Link>
```

```jsx React icon="react"
import { usePage } from '@inertiajs/react'

const { url, component } = usePage()

// URL exact match...
<a href="/users" >Users</a>

// Component exact match...
<a href="/users" >Users</a>

// URL starts with (/users, /users/create, /users/1, etc.)...
<a href="/users" >Users</a>

// Component starts with (Users/Index, Users/Create, Users/Show, etc.)...
<a href="/users" >Users</a>
```

```svelte Svelte icon="s"
import { page } from '@inertiajs/svelte'

// URL exact match...
<a href="/users" class={$page.url === '/users' ? 'active' : ''}>Users</a>

// Component exact match...
<a href="/users" class={$page.component === 'Users/Index' ? 'active' : ''}>Users</a>

// URL starts with (/users, /users/create, /users/1, etc.)...
<a href="/users" class={$page.url.startsWith('/users') ? 'active' : ''}>Users</a>

// Component starts with (Users/Index, Users/Create, Users/Show, etc.)...
<a href="/users" class={$page.component.startsWith('Users') ? 'active' : ''}>Users</a>
```

</CodeGroup>

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

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

---

## File: v1/the-basics/manual-visits.mdx

---
title: Manual Visits
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

In addition to [creating links](/v1/the-basics/links), it's also possible to manually make Inertia visits / requests programmatically via JavaScript. This is accomplished via the `router.visit()` method.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

The `reload()` method is a convenient, shorthand method that automatically visits the current page with `preserveState` and `preserveScroll` both set to `true`, making it the perfect method to invoke when you just want to reload the current page's data.

## Method

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

Uploading files via `put` or `patch` is not supported in Laravel. Instead, make the request via `post`, including a `_method` field set to `put` or `patch`. This is called [form method spoofing](https://laravel.com/docs/8.x/routing#form-method-spoofing).

## Data

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

For convenience, the `get()`, `post()`, `put()`, and `patch()`methods all accept `data` as their second argument.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

## Custom Headers

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

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

## File Uploads

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

For more information on uploading files, please consult the dedicated [file uploads](/v1/the-basics/file-uploads) documentation.

## Browser History

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

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

## State Preservation

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

However, in some situations, it's necessary to preserve the page component state. For example, when submitting a form, you need to preserve your form data in the event that form validation fails on the server.

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

You can instruct Inertia to preserve the component's state when using the `get` method by setting the `preserveState` option to `true`.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

If you'd like to only preserve state if the response includes validation errors, set the `preserveState` option to "errors".

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post('/users', data, {
    preserveState: (page) => page.props.someProp === 'value',
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.post('/users', data, {
    preserveState: (page) => page.props.someProp === 'value',
})
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.post('/users', data, {
    preserveState: (page) => page.props.someProp === 'value',
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.post('/users', data, {
    preserveState: (page) => page.props.someProp === 'value',
})
```

</CodeGroup>

## Scroll Preservation

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-management#scroll-regions) you've defined) back to the top of the page.

You can disable this behavior by setting the `preserveScroll` option to `false`.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.visit(url, { preserveScroll: false })
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.visit(url, { preserveScroll: false })
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.visit(url, { preserveScroll: false })
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.visit(url, { preserveScroll: false })
```

</CodeGroup>

If you'd like to only preserve the scroll position if the response includes validation errors, set the `preserveScroll` option to "errors".

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.visit(url, { preserveScroll: 'errors' })
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.visit(url, { preserveScroll: 'errors' })
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.visit(url, { preserveScroll: 'errors' })
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.visit(url, { preserveScroll: 'errors' })
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.post('/users', data, {
    preserveScroll: (page) => page.props.someProp === 'value',
})
```

</CodeGroup>

For more information regarding this feature, please consult the [scroll management](/v1/advanced/scroll-management) documentation.

## Partial Reloads

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

For more information on this feature, please consult the [partial reloads](/v1/advanced/partial-reloads) documentation.

## Visit Cancellation

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

// Cancel the visit...
this.cancelToken.cancel()
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

// Cancel the visit...
this.cancelToken.cancel()
```

```js React icon="react"
import { router } from '@inertiajs/react'

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

// Cancel the visit...
this.cancelToken.cancel()
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

// Cancel the visit...
this.cancelToken.cancel()
```

</CodeGroup>

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

## Event Callbacks

In addition to Inertia's [global events](/v1/advanced/events), Inertia also provides a number of per-visit event callbacks.

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.delete(`/users/${user.id}\
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.delete(`/users/${user.id}\
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.delete(`/users/${user.id}\
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.delete(`/users/${user.id}\
```

</CodeGroup>

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

router.post(url, {
    onSuccess: () => {
        return Promise.all([
            this.doThing(),
            this.doAnotherThing()
        ])
    }
    onFinish: visit => {
        // This won't be called until doThing()
        // and doAnotherThing() have finished.
    },
})
```

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

router.post(url, {
    onSuccess: () => {
        return Promise.all([
            this.doThing(),
            this.doAnotherThing()
        ])
    }
    onFinish: visit => {
        // This won't be called until doThing()
        // and doAnotherThing() have finished.
    },
})
```

```js React icon="react"
import { router } from '@inertiajs/react'

router.post(url, {
    onSuccess: () => {
        return Promise.all([
            this.doThing(),
            this.doAnotherThing()
        ])
    }
    onFinish: visit => {
        // This won't be called until doThing()
        // and doAnotherThing() have finished.
    },
})
```

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

router.post(url, {
    onSuccess: () => {
        return Promise.all([
            this.doThing(),
            this.doAnotherThing()
        ])
    }
    onFinish: visit => {
        // This won't be called until doThing()
        // and doAnotherThing() have finished.
    },
})
```

</CodeGroup>

---

## File: v1/the-basics/pages.mdx

---
title: Pages
---

import { ReactSpecific } from "/snippets/react-specific.jsx"
import { SvelteSpecific } from "/snippets/svelte-specific.jsx"
import { VueSpecific } from "/snippets/vue-specific.jsx"

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

## Creating Pages

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

<CodeGroup>

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

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

export default {
    components: {
        Head,
        Layout,
    },
    props: {
        user: Object,
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import Layout from './Layout'
import { Head } from '@inertiajs/vue3'

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

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

```jsx React icon="react"
import Layout from './Layout'
import { Head } from '@inertiajs/react'

export default function Welcome({ user }) {
    return (
        <Layout>
            <Head title="Welcome" />
            <h1>Welcome</h1>
            <p>Hello {user.name}, welcome to your first Inertia app!</p>
        </Layout>
    )
}
```

```html Svelte icon="s"
<script>
    import Layout from './Layout.svelte'

    export let user
</script>

<Layout>
    <svelte:head>
        <title>Welcome</title>
    </svelte:head>
    <H1>Welcome</H1>
    <p>Hello {user.name}, welcome to your first Inertia app!</p>
</Layout>
```

</CodeGroup>

<ClientSpecific>
Given the page above, you can render the page by returning an [Inertia response](/v1/the-basics/responses) from a controller or route. In this example, let's assume this page is stored at <VueSpecific>`resources/js/Pages/User/Show.vue`</VueSpecific><ReactSpecific>`resources/js/Pages/User/Show.jsx`</ReactSpecific><SvelteSpecific>`resources/js/Pages/User/Show.svelte`</SvelteSpecific>within a Laravel application.
</ClientSpecific>

```php
use Inertia\Inertia;

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

## Creating Layouts

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <main>
        <header>
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/contact">Contact</a>
        </header>
        <article>
            <slot />
        </article>
    </main>
</template>

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

export default {
    components: {
        Link,
    }
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

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

```jsx React icon="react"
import { Link } from '@inertiajs/react'

export default function Layout({ children }) {
    return (
        <main>
            <header>
                <a href="/">Home</a>
                <a href="/about">About</a>
                <a href="/contact">Contact</a>
            </header>
            <article>{children}</article>
        </main>
    )
}
```

```html Svelte icon="s"
<script>
    import { inertia } from '@inertiajs/svelte'
</script>

<main>
    <header>
        <a use:inertia href="/">Home</a>
        <a use:inertia href="/about">About</a>
        <a use:inertia href="/contact">Contact</a>
    </header>
    <article>
        <slot />
    </article>
</main>
```

</CodeGroup>

<ClientSpecific>
As you can see, there is nothing Inertia specific within this template. This is just a typical <VueSpecific>Vue</VueSpecific><ReactSpecific>React</ReactSpecific><SvelteSpecific>Svelte</SvelteSpecific> component.
</ClientSpecific>

## Persistent Layouts

While it's simple to implement layouts as children of page components, it forces the layout instance to be destroyed and recreated between visits. This means you cannot have persistent layout state when navigating between pages.

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <div>
        <H1>Welcome</H1>
        <p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
    </div>
</template>

<script>
import Layout from './Layout'

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

    // Using shorthand syntax...
    layout: Layout,

    props: {
        user: Object,
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script>
import Layout from './Layout'

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

    // Using shorthand syntax...
    layout: Layout,
}
</script>

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

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

```jsx React icon="react"
import Layout from './Layout'

const Home = ({ user }) => {
    return (

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

    )
}

Home.layout = page => <Layout children={page} title="Welcome" />

export default Home
```

```html Svelte icon="s"
<script context="module">
    export { default as layout } from './Layout.svelte'
</script>

<script>
    export let user
</script>

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

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <div>
        <H1>Welcome</H1>
        <p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
    </div>
</template>

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

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

    // Using shorthand syntax...
    layout: [SiteLayout, NestedLayout],

    props: {
        user: Object,
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script>
import SiteLayout from './SiteLayout'
import NestedLayout from './NestedLayout'

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

    // Using the shorthand...
    layout: [SiteLayout, NestedLayout],
}
</script>

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

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

```jsx React icon="react"
import SiteLayout from './SiteLayout'
import NestedLayout from './NestedLayout'

const Home = ({ user }) => {
    return (

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

    )
}

Home.layout = page => (
    <SiteLayout title="Welcome">
        <NestedLayout children={page} />
    </SiteLayout>
)

export default Home
```

```html Svelte icon="s"
<script context="module">
    import SiteLayout from './SiteLayout.svelte'
    import NestedLayout from './NestedLayout.svelte'
    export const layout = [SiteLayout, NestedLayout]
</script>

<script>
    export let user
</script>

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

</CodeGroup>

<VueSpecific>
If you're using Vue 2.7 or Vue 3, you can alternatively use the [defineOptions plugin](https://vue-macros.sxzz.moe/macros/define-options.html) to define a layout within `<script setup>`:

```html
<script setup>
import Layout from './Layout'
defineOptions({ layout: Layout })
</script>
```
</VueSpecific>

## Default layouts

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import Layout from './Layout'

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

```js Vue 3 icon="vuejs"
import Layout from './Layout'

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

```js React icon="react"
import Layout from './Layout'

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

```js Svelte icon="s"
import Layout from './Layout'

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

</CodeGroup>

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

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import Layout from './Layout'

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

```js Vue 3 icon="vuejs"
import Layout from './Layout'

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

```js React icon="react"
import Layout from './Layout'

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

```js Svelte icon="s"
import Layout from './Layout'

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

</CodeGroup>

---

## File: v1/the-basics/redirects.mdx

---
title: Redirects
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

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

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

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

## 303 Response Code

When redirecting after a `PUT`, `PATCH`, or `DELETE` request, you must use a `303` response code, otherwise the subsequent request will not be treated as a `GET`request. A `303` redirect is very similar to a `302` redirect; however, the follow-up request is explicitly changed to a `GET` request.

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

## External Redirects

Sometimes it's necessary to redirect to an external website, or even another non-Inertia endpoint in your app while handling an Inertia request. This can be accomplished using a server-side initiated `window.location` visit via the `Inertia::location()` method.

```php
return Inertia::location($url);
```

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

---

## File: v1/the-basics/responses.mdx

---
title: Responses
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Creating Responses

Creating an Inertia response is simple. To get started, invoke the `Inertia::render()` method within your controller or route, providing both the name of the [JavaScript page component](/v1/the-basics/pages) that you wish to render, as well as any props (data) for the page.

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

```php
use Inertia\Inertia;

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

        // Alternatively, you can use the inertia() helper...
        return inertia('Event/Show', [
            'event' => $event->only(
                'id',
                'title',
                'start_date',
                'description'
            ),
        ]);
    }
}
```

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

```php
return Inertia::render('Event', ['event' => $event])
    ->withViewData(['meta' => $event->meta]);
```

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

---

## File: v1/the-basics/routing.mdx

---
title: Routing
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## Defining Routes

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

## Shorthand Routes

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.

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

## Generating URLs

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

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

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

However, when using Laravel, the [Ziggy](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.

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.

<CodeGroup>

```js Vue 2 icon="vuejs"
Vue.prototype.$route = route
```

```js Vue 3 icon="vuejs"
app.config.globalProperties.$route = route
```

</CodeGroup>

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

---

## File: v1/the-basics/shared-data.mdx

---
title: Shared Data
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

## Sharing Data

Inertia's server-side adapters all provide a method of making shared data available for every request. This is typically done outside of your controllers. Shared data will be automatically merged with the page props provided in your controller.

In Laravel applications, this is typically handled by the `HandleInertiaRequests` middleware that is automatically installed when installing the [server-side adapter](/server-side-setup#middleware).

```php
class HandleInertiaRequests extends Middleware
{
    public function share(Request $request)
    {
        return array_merge(parent::share($request), [
            // Synchronously...
            'appName' => config('app.name'),

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

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

```php
use Inertia\Inertia;

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

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

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

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

## Accessing Shared Data

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.

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <main>
        <header>
            You are logged in as: {{ user.name }}
        </header>
        <article>
            <slot />
        </article>
    </main>
</template>

<script>
export default {
    computed: {
        user() {
            return this.$page.props.auth.user
        }
    }
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'

const page = usePage()

const user = computed(() => page.props.auth.user)
</script>

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

```jsx React icon="react"
import { usePage } from '@inertiajs/react'

export default function Layout({ children }) {
    const { auth } = usePage().props

    return (
        <main>
            <header>
                You are logged in as: {auth.user.name}
            </header>
            <article>
                {children}
            </article>
        </main>
    )
}
```

```html Svelte icon="s"
<script>
    import { page } from '@inertiajs/svelte'
</script>

<main>
    <header>
        You are logged in as: {$page.props.auth.user.name}
    </header>
    <article>
        <slot />
    </article>
</main>
```

</CodeGroup>

## Flash Messages

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

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

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

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
<template>
    <main>
        <header></header>
        <article>
            <div v-if="$page.props.flash.message" class="alert">
                {{ $page.props.flash.message }}
            </div>
            <slot />
        </article>
        <footer></footer>
    </main>
</template>
```

```vue Vue 3 icon="vuejs"
<template>
    <main>
        <header></header>
        <article>
            <div v-if="$page.props.flash.message" class="alert">
                {{ $page.props.flash.message }}
            </div>
            <slot />
        </article>
        <footer></footer>
    </main>
</template>
```

```jsx React icon="react"
import { usePage } from '@inertiajs/react'

export default function Layout({ children }) {
    const { flash } = usePage().props

    return (
        <main>
            <header></header>
            <article>
                {flash.message && (
                    <div class="alert">{flash.message}</div>
                )}
                {children}
            </article>
            <footer></footer>
        </main>
    )
}
```

```html Svelte icon="s"
<script>
    import { page } from '@inertiajs/svelte'
</script>

<main>
    <header></header>
    <article>
        {#if $page.props.flash.message}
            <div class="alert">{$page.props.flash.message}</div>
        {/if}
        <slot />
    </article>
    <footer></footer>
</main>
```

</CodeGroup>

---

## File: v1/the-basics/title-and-meta.mdx

---
title: Title & Meta
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

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

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

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

## Head Component

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Head } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Head } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Head } from '@inertiajs/react'

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

```html Svelte icon="s"
<svelte:head>
    <title>Your page title</title>
    <meta name="description" content="Your page description" />
</svelte:head>
```

</CodeGroup>

## Title Shorthand

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Head } from '@inertiajs/vue2'

<Head title="Your page title" />
```

```vue Vue 3 icon="vuejs"
import { Head } from '@inertiajs/vue3'

<Head title="Your page title" />
```

```jsx React icon="react"
import { Head } from '@inertiajs/react'

<Head title="Your page title" />
```

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

## Title Callback

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

```js
createInertiaApp({
title: title => \
```

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Head } from '@inertiajs/vue2'

<Head title="Home">
```

```vue Vue 3 icon="vuejs"
import { Head } from '@inertiajs/vue3'

<Head title="Home">
```

```jsx React icon="react"
import { Head } from '@inertiajs/react'

<Head title="Home">
```

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

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

```html
<title>Home - My App</title>
```

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import { Head } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
import { Head } from '@inertiajs/vue3'

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

```jsx React icon="react"
import { Head } from '@inertiajs/react'

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

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

## Multiple Head Instances

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
// Layout.vue

import { Head } from '@inertiajs/vue2'

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

// About.vue

import { Head } from '@inertiajs/vue2'

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

```vue Vue 3 icon="vuejs"
// Layout.vue

import { Head } from '@inertiajs/vue3'

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

// About.vue

import { Head } from '@inertiajs/vue3'

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

```jsx React icon="react"
// Layout.js

import { Head } from '@inertiajs/react'

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

// About.js

import { Head } from '@inertiajs/react'

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

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

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

The code example above will render the following HTML.

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

## Head Extension

When building a real application, it can sometimes be helpful to create a custom head component that extends Inertia's `<Head>` component. This gives you a place to set app-wide defaults, such as appending the app name to the page title.

<CodeGroup>

```vue Vue 2 icon="vuejs"
<!-- AppHead.vue -->

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

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

export default {
    components: {
        Head,
    },
    props: {
        title: String,
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<!-- AppHead.vue -->

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

defineProps({ title: String })
</script>

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

```jsx React icon="react"
// AppHead.js

import { Head } from '@inertiajs/react'

const Site = ({ title, children }) => {
    return (
        <Head>
            <title>{title ? `${title} - My App` : 'My App'}</title>
            {children}
        </Head>
    )
}

export default Site
```

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

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

<CodeGroup>

```vue Vue 2 icon="vuejs"
import AppHead from './AppHead'

<AppHead title="About" />
```

```vue Vue 3 icon="vuejs"
import AppHead from './AppHead'

<AppHead title="About" />
```

```jsx React icon="react"
import AppHead from './AppHead'

<AppHead title="About">
```

```js Svelte icon="s"
// Not supported
```

</CodeGroup>

---

## File: v1/the-basics/validation.mdx

---
title: Validation
---

import V1EOLWarning from "/snippets/v1-eol-warning.mdx";

<V1EOLWarning />

## How It Works

Handling server-side validation errors in Inertia works differently than a classic XHR-driven form that requires you to catch the validation errors from `422` responses and manually update the form's error state - because Inertia never receives `422` responses. Instead, Inertia operates much more like a standard full page form submission. Here's how:

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

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

Finally, since Inertia apps never generate `422` responses, Inertia needs another way to determine if a response includes validation errors. To do this, Inertia checks the `page.props.errors` object for the existence of any errors. In the event that errors are present, the request's `onError()` callback will be called instead of the `onSuccess()` callback.

## Sharing Errors

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

## Displaying Errors

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

<CodeGroup>

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

<script>
import { router } from '@inertiajs/vue2'

export default {
    props: {
        errors: Object,
    },
    data() {
        return {
            form: {
                first_name: null,
                last_name: null,
                email: null,
            },
        }
    },
    methods: {
        submit() {
            router.post('/users', this.form)
        },
    },
}
</script>
```

```vue Vue 3 icon="vuejs"
<script setup>
import { reactive } from 'vue'
import { router } from '@inertiajs/vue3'

defineProps({ errors: Object })

const form = reactive({
    first_name: null,
    last_name: null,
    email: null,
})

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

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

```jsx React icon="react"
import { useState } from 'react'
import { router, usePage } from '@inertiajs/react'

export default function Edit() {
    const { errors } = usePage().props

    const [values, setValues] = useState({
        first_name: null,
        last_name: null,
        email: null,
    })

    function handleChange(e) {
        setValues(values => ({
            ...values,
            [e.target.id]: e.target.value,
        }))
    }

    function handleSubmit(e) {
        e.preventDefault()
        router.post('/users', values)
    }

    return (
        <form onSubmit={handleSubmit}>
            <label for="first_name">First name:</label>
            <input id="first_name" value={values.first_name} onChange={handleChange} />
            {errors.first_name && <div>{errors.first_name}</div>}
            <label for="last_name">Last name:</label>
            <input id="last_name" value={values.last_name} onChange={handleChange} />
            {errors.last_name && <div>{errors.last_name}</div>}
            <label for="email">Email:</label>
            <input id="email" value={values.email} onChange={handleChange} />
            {errors.email && <div>{errors.email}</div>}
            <button type="submit">Submit</button>
        </form>
    )
}
```

```html Svelte icon="s"
<script>
    import { router } from '@inertiajs/svelte'

    export let errors = {}

    let values = {
        first_name: null,
        last_name: null,
        email: null,
    }

    function handleSubmit() {
        router.post('/users', values)
    }
</script>

<form on:submit|preventDefault={handleSubmit}>
    <label for="first_name">First name:</label>
    <input id="first_name" bind:value={values.first_name}>
    {#if errors.first_name}<div>{errors.first_name}</div>{/if}

    <label for="last_name">Last name:</label>
    <input id="last_name" bind:value={values.last_name}>
    {#if errors.last_name}<div>{errors.last_name}</div>{/if}

    <label for="email">Email:</label>
    <input id="email" bind:value={values.email}>
    {#if errors.email}<div>{errors.email}</div>{/if}

    <button type="submit">Submit</button>
</form>
```

</CodeGroup>

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

## Repopulating Input

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

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

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

## Error Bags

If you're using the [form helper](/forms#form-helper), it's not necessary to use error bags since validation errors are automatically scoped to the form object making the request.

For pages that have more than one form, it's possible to encounter conflicts when displaying validation errors if two forms share the same field names. For example, imagine a "create company" form and a "create user" form that both have a `name` field. Since both forms will be displaying the `page.props.errors.name` validation error, generating a validation error for the `name`field in either form will cause the error to appear in both forms.

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

<CodeGroup>

```js Vue 2 icon="vuejs"
import { router } from '@inertiajs/vue2'

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

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

```js Vue 3 icon="vuejs"
import { router } from '@inertiajs/vue3'

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

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

```js React icon="react"
import { router } from '@inertiajs/react'

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

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

```js Svelte icon="s"
import { router } from '@inertiajs/svelte'

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

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

</CodeGroup>

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

---

## File: v2/advanced/asset-versioning.mdx

---
title: Asset Versioning
---

import V2UpgradeWarning from "/snippets/v2-upgrade-warning.mdx";

<V2UpgradeWarning />

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

## Configuration

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

Typically, your application's asset version can be specified within the `version` method of the Inertia `HandleInertiaRequests` middleware.

```php
class HandleInertiaRequests extends Middleware
{
    public function version(Request $request)
    {
        return parent::version($request);
    }
}
```

Alternatively, the asset version can be provided manually using the `Inertia::version()` method.

```php
use Inertia\Inertia;

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

## Cache Busting

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

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.

## Manual Refreshing

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.

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).

```php
class HandleInertiaRequests extends Middleware
{
    public function version(Request $request)
    {
        return null;
    }

    public function share(Request $request)
    {
        return array_merge(parent::share($request), [
            'version' => parent::version($request),
        ]);
    }
}
```

On the frontend, you can watch the `version` property and show a notification when a new version is detected.

---

## File: v2/advanced/code-splitting.mdx

---
title: Code Splitting
---

import V2UpgradeWarning from "/snippets/v2-upgrade-warning.mdx";

<V2UpgradeWarning />

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.

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.

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.

## Using Vite

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.

<CodeGroup>

```js Vue icon="vuejs"
resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.vue', { eager: true }) // [!code --:2]
    return pages[`./Pages/${name}.vue`]
    const pages = import.meta.glob('./Pages/**/*.vue') // [!code ++:2]
    return pages[`./Pages/${name}.vue`]()
},
```

```js React icon="react"
resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true }) // [!code --:2]
    return pages[`./Pages/${name}.jsx`]
    const pages = import.meta.glob('./Pages/**/*.jsx') // [!code ++:2]
    return pages[`./Pages/${name}.jsx`]()
},
```

```js Svelte icon="s"
resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true }) // [!code --:2]
    return pages[`./Pages/${name}.svelte`]
    const pages = import.meta.glob('./Pages/**/*.svelte') // [!code ++:2]
    return pages[`./Pages/${name}.svelte`]()
},
```

</CodeGroup>

## Using Webpack

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.

```bash
npm install @babel/plugin-syntax-dynamic-import
```

Next, create a `.babelrc` file in your project with the following configuration:

```json
{
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
}
```

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.

Finally, update the `resolve` callback in your app's initialization code to use `import`instead of `require`.

<CodeGroup>

```js Vue icon="vuejs"
resolve: name => require(`./Pages/${name}`), // [!code --]
resolve: name => import(`./Pages/${name}`), // [!code ++]
```

```js React icon="react"
resolve: name => require(`./Pages/${name}`), // [!code --]
resolve: name => import(`./Pages/${name}`), // [!code ++]
```

```js Svelte icon="s"
resolve: name => require(`./Pages/${name}.svelte`), // [!code --]
resolve: name => import(`./Pages/${name}.svelte`), // [!code ++]
```

</CodeGroup>

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.

```js
output: {
    chunkFilename: 'js/[name].js?id=[chunkhash]',
}
```

---

## File: v2/advanced/error-handling.mdx

---
title: Error Handling
---

import V2UpgradeWarning from "/snippets/v2-upgrade-warning.mdx";

<V2UpgradeWarning />

## Development

One of the advantages to working with a robust server-side framework is the built-in exception handling you get for free. For example, Laravel ships with a beautiful error reporting tool which displays a nicely formatted stack trace in local development.

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

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

## Dialog Element

By default, Inertia displays error modals using a custom `` overlay. However, you can opt-in to using the native HTML `<dialog>` element instead, which provides built-in modal functionality including backdrop handling.

To enable this, configure the `future.useDialogForErrorModal` option in your [application defaults](/v2/installation/client-side-setup#configuring-defaults).

```js
createInertiaApp({
    // resolve, setup, etc.
    defaults: {
        future: {
            useDialogForErrorModal: true,
        },
    },
})
```

## Production

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

When building Laravel applications, you can accomplish this by using the `respond` exception method in your application's `bootstrap/app.php` file.

```php
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Inertia\Inertia;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
        if (! app()->environment(['local', 'testing']) && in_array($response->getStatusCode(), [500, 503, 404, 403])) {
            return Inertia::render('ErrorPage', ['status' => $response->getStatusCode()])
                ->toResponse($request)
                ->setStatusCode($response->getStatusCode());
        }

        if ($response->getStatusCode() === 419) {
            return back()->with([
                'message' => 'The page expired, please try again.',
            ]);
        }

        return $response;
    });
})
```

You may have noticed we're returning an `ErrorPage` 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.

<CodeGroup>

```vue Vue icon="vuejs"
<script setup>
import { computed } from 'vue'

const props = defineProps({ status: Number })

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

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

<template>
    <div>
        <h1>{{ title }}</h1>
        <div>{{ description }}</div>
    </div>
</template>
```

```jsx React icon="react"
export default function ErrorPage({ status }) {
    const title = {
        503: '503: Service Unavailable',
        500: '500: Server Error',
        404: '404: Page Not Found',
        403: '403: Forbidden',
    }[status]

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

    return (
        <div>
            <H1>{title}</H1>
            <div>{description}</div>
        </div>
    )
}
```

```svelte Svelte 4 icon="s"
<script>
    export let status

    $: title = {
        503: '503: Service Unavailable',
        500: '500: Server Error',
        404: '404: Page Not Found',
        403: '403: Forbidden',
    }[status]

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

<div>
    <h1>{title}</h1>
    <div>{description}</div>
</div>
```

```svelte Svelte 5 icon="s"
<script>
    let { status } = $props()

    const title = {
        503: '503: Service Unavailable',
        500: '500: Server Error',
        404: '404: Page Not Found',
        403: '403: Forbidden',
    }

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

<div>
    <h1>{title[status]}</h1>
    <div>{description[status]}</div>
</div>
```

</CodeGroup>