Pages

With Inertia, each page in your application has its own controller and corresponding JavaScript component. This allows you to retrieve just the data necessary for that page, no API required.

Creating pages

Pages are simply JavaScript components. There is nothing particularly special about them. Pages receive data from the controllers as props. Here's an example of a simple page component.

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

<script>
  import Layout from './Layout'

  export default {
    components: {
      Layout,
    },
    props: {
      user: Object,
    },
  }
</script>

Creating layouts

While not required, for most projects it makes sense to create a site layout that your pages can extend. Notice in our page example above that we're wrapping the page content within a <layout> component. Here's an example of such a component. There is nothing Inertia specific here. This is just a standard JavaScript component.

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

<script>
  export default {
    props: {
      title: String,
    },
    watch: {
      title: {
        immediate: true,
        handler(title) {
          document.title = title
        },
      },
    },
  }
</script>
The <inertia-link> component is automatically registered by the Inertia plugin.

Persistent layouts

While it's simple to implement layouts as children of the page components, it does force 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 navigation between page visits. In these situations, using the persistent layouts feature in Inertia is a better choice.

<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 the shorthand
    layout: Layout,

    props: {
      user: Object,
    },
  }
</script>

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

<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 the shorthand
    layout: [SiteLayout, NestedLayout],

    props: {
      user: Object,
    },
  }
</script>

Default layouts

If you're using persistent layouts, it's possible to set a default page layout in the resolveComponent() callback.

import Layout from './Layout'

resolveComponent: name => import(`./Pages/${name}`)
  .then(({ default: page }) => {
    page.layout = page.layout === undefined ? Layout : page.layout
    return page
  }),

This will automatically set the page layout to Layout if a layout has not already been set for that page. If needed, you can disable the default layout on specific pages by setting the layout to null.

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

import Layout from './Layout'

resolveComponent: name => import(`./Pages/${name}`)
  .then(({ default: page }) => {
    if (page.layout === undefined && !name.startsWith('Public/')) {
      page.layout = Layout
    }
    return page
  }),

Title and meta tags

While it's possible to pass title and meta tag props from pages to layouts (as illustrated above), it's often easier to manage this using a document head library like Vue Meta or React Helmet. Svelte has built-in support for manipulating the document head with the <svelte:head> element.

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

<script>
  import Layout from './Layout'

  export default {
    metaInfo() {
      return {
        title: `Welcome ${this.user.name}`,
      }
    },
    components: {
      Layout,
    },
    props: {
      user: Object,
    },
  }
</script>
Don't forget to install and configure the Vue Meta package.

Further, if it's critical for your application to set the page title and meta tags server-side, you can use root template data to accomplish this.