Back to Course |
Vue Inertia + Laravel 11: From Scratch

Extract Repeating Menus as Main Layout

Let's start talking about layouts. Our current main problem is duplication of the menu code for Posts and About pages.


Main Layout: Vue Component

First, we need a Vue component as the main layout. We will create a new folder resources/js/Layouts and a Vue component, App.vue inside it.

Move the repeating code from the Posts/Index.vue and About.vue Vue components to the Layouts/App.vue Vue component.

resources/js/Pages/Posts/Index.vue:

<script setup>
import { Link } from '@inertiajs/vue3';
 
const props = defineProps({
posts: {
type: Object,
required: true
}
})
</script>
 
<template>
<div class="mb-4">
<Link class="mr-2" :href="route('posts.index')">Posts</Link>
<Link :href="route('about')">About</Link>
</div>
 
// ...
</template>

resources/js/Pages/About.vue:

<script setup>
import { Link } from '@inertiajs/vue3';
</script>
 
<template>
<div class="mb-4">
<Link class="mr-2" :href="route('posts.index')">Posts</Link>
<Link :href="route('about')">About</Link>
</div>
 
<div>About us</div>
</template>

resources/js/Layouts/App.vue:

<script setup>
import { Link } from '@inertiajs/inertia-vue3'
</script>
 
<template>
<div class="mb-4">
<Link class="mr-2" :href="route('posts.index')">Posts</Link>
<Link :href="route('about')">About</Link>
</div>
</template>

To tell Vue where to add the content, use slots, the same as with Blade.

resources/js/Layouts/App.vue:

<script setup>
import { Link } from '@inertiajs/inertia-vue3'
</script>
 
<template>
<div class="mb-4">
<Link class="mr-2" :href="route('posts.index')">Posts</Link>
<Link :href="route('about')">About</Link>
</div>
 
<slot />
</template>

Using Vue Layout

How do you use that App layout? We must import it into the Vue component and surround everything with it.

Also, we can use different name when importing and then surround with that name. I choose the AppLayout name.

resources/js/Pages/Posts/Index.vue:

<script setup>
import AppLayout from '../../Layouts/App.vue';
 
const props = defineProps({
posts: {
type: Object,
required: true
}
})
</script>
 
<template>
<AppLayout>
<table class="min-w-full divide-y divide-gray-200 border">
// ...
</AppLayout>
</template>

resources/js/Pages/About.vue:

<script setup>
import AppLayout from '../Layouts/App.vue';
</script>
 
<template>
<AppLayout>
<div>About us</div>
</AppLayout>
</template>

Visually, nothing changes, but now we don't have duplicate code.


Active Links: CSS Class

In this lesson, "along the way", let's also add a CSS class to indicate which links in the menu are active.

There are a few ways to do that. In this lesson, we will use the route() function to check if the route is active.

resources/js/Layouts/App.vue:

// ...
 
<template>
<div class="mb-4">
<Link class="mr-2" :href="route('posts.index')">Posts</Link>
<Link :href="route('about')">About</Link>
<Link class="mr-2" :href="route('posts.index')" :class="{ 'font-bold underline': route().current('posts.index') }">Posts</Link>
<Link :href="route('about')" :class="{ 'underline': route().current('about') }">About</Link>
</div>
 
<slot />
</template>


Now, we have one main layout with the links, and from that layout, we build all the pages in the future lessons.