With most applications, it makes sense to have at least one layout that we can use across all our pages to easily apply things like navbars, authentication states, and the like. They also help keep things consistent when traveling from page to page.
What Not To Do
Your first notion when applying a layout may be to just import and wrap each page with the layout component. Something like the below.
<template> <default-layout> <h1>My Home Page</h1> </default-layout> </template> <script> import DefaultLayout from '../Layouts/Default.vue' export default { components: { DefaultLayout } } </script>
Copied!
However, using this approach will result in our layout needing to be re-rendered repeatedly as our users switch between pages since the layout itself is a part of the page’s content. Not to mention, we need to manually apply the layout for each page. So, although this approach does work it’s less than optimal.
The InertiaJS Layout Property
InertiaJS actually supports layouts out of the box. When we define our page component, InertiaJS will check it for a layout
property. If the layout
property is a Vue component, that component will be used as the layout for the page and the page itself will be rendered within the layout’s <slot />
content.
Meaning, that we can alter our above example to the below; achieving the same results in a more performant manner because InertiaJS will only swap out the layout component when it’s changed.
<template> <div> <h1>My Home Page</h1> </div> </template> <script> import DefaultLayout from '../Layouts/Default.vue' export default { layout: DefaultLayout } </script>
Copied!
InertiaJS Layouts & Vue 3 Setup Scripts
You may be wondering what to do with pages where you’re using a Vue 3 setup script since those don’t have export default
objects.
You may attempt to reach for defineExpose
, since that can be used to expose properties outside of the component’s setup, but unfortunately that doesn’t work for this use case.
Instead, we’ll want to add a secondary script that does utilize export default
and export the layout
property that way.
<template> <div> <h1>My Home Page</h1> <div>{{ testing }}</div> </div> </template> <script> import DefaultLayout from '../Layouts/Default.vue' export default { layout: DefaultLayout } </script> <script setup> import { ref } from 'vue' const testing = ref('test') </script>
Copied!
It’s not pretty, but it works. Additionally, we'll discuss applying default layouts a little later in this lesson. This will allow us to bypass defining a layout on the vast majority of our pages, so this won’t be as big of an issue.
Defining A Layout
So, what does this DefaultLayout
component actually look like? Well, it can be as complex, including nested layouts and render functions, or simple as you need. The main thing to keep in mind is that it will need to have a default slot so that the page's content can be included.
A typical application layout might include a navbar, alert and dialog helpers, and things of that nature. Below is a basic example.
<template> <main> <!-- simple navbar --> <header class="flex items-center justify-between"> <div>Adonis + Inertia</div> <nav class="grid gap-3 grid-cols-3"> <Link href="/page-1">Page 1</Link> <Link href="/page-2">Page 2</Link> <Link href="/page-3">Page 3</Link> </nav> <div class="flex justify-end"> <Link href="/login">Login</Link> <Link href="/register">Register</Link> </div> </header> <!-- page content --> <slot /> </main> </template> <script setup> // resources/js/Layouts/Default.vue </script>
Copied!
In some cases, you may need a second layout. For example, if the user needs to be authenticated to get into the application, then it’s likely the default layout is going to utilize some user information. However, on our authentication pages, that’s not needed.
So, we can create a second layout specifically for these pages.
<template> <div class="flex flex-col items-center justify-center w-full h-full max-w-sm mx-auto pt-12"> <h1 class="text-center"> Adonis + Inertia </h1> <div class="w-full bg-white p-6 rounded-xl shadow-xl"> <slot /> </div> </div> </template> <script setup> // resources/js/Layouts/Auth.vue </script> <style> body { background: theme('colors.gray.100'); } </style>
Copied!
Setting An Inertia Default Layout
So far, we’ve been defining all our layouts within our page components. This is beneficial when you have more complex layouts. However, we can set up our pages to where anytime we don’t specify a particular layout to use, it’ll use our default layout.
To do this, we’ll need to slightly alter the resolve
method within our app.js
file. Remember, this method is used to grab the page component from our project and return it to Inertia.
import '../css/app.css' import { createApp, h } from 'vue' import { createInertiaApp } from '@inertiajs/inertia-vue3' import DefaultLayout from './Layouts/Default.vue' // 👈 1. import the default layout createInertiaApp({ resolve: name => { // 2. get the page component const page = require(`./Pages/${name}`).default // 3. set the default layout, if a layout isn't defined if (!page.layout) { page.layout = DefaultLayout } // 4. return the page return page }, setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .mount(el) }, })
Copied!
- resources
- js
- app.js
All we need to do is import our DefaultLayout
, check to see if the imported page component is defining a layout. If it’s not, we’ll define our DefaultLayout
. Then, we’ll return the page for InertiaJS to use.
Using The Default Layout
Now, in order to make use of this, all we need to do is completely remove anything layout-based within our pages.
<template> <div> <h1>My Home Page</h1> <div>{{ testing }}</div> </div> </template> <script setup> import { ref } from 'vue' const testing = ref('test') </script>
Copied!
This means that we’ll no longer need to use the second script when using a setup script.
Using A Secondary Layout
When it comes to using a secondary layout, like our AuthLayout
, instead of the default layout, all we need to do is import and define the layout
property as we were before.
<template> <div> <h1>Login</h1> </div> </template> <script> import AuthLayout from '../Layouts/Auth.vue' export default { layout: AuthLayout } </script>
Copied!
Now our AuthLayout
will be used for our login page instead of the DefaultLayout
.
Join The Discussion! (2 Comments)
Please sign in or sign up for free to join in on the dicussion.
ericpugh
Upvote for a V6 version of this tutorial (now that the inertia package is supported by the Adonis team)
Please sign in or sign up for free to reply
tomgobich
Hey Eric! An updated version of this series is on the way, being planned now, and will begin shortly after we finish our Let's Learn AdonisJS 6 series :)
Please sign in or sign up for free to reply