Click from one page to the next and your sidebar scroll jumps back to the top, an open menu snaps shut, and an audio player stops. That is a layout being rebuilt on every visit. The Vue starter kit already avoids it; here is how, and how to fix an older app.
TL;DR
- Wrapping each page in
<AppLayout>inside the template remounts the shell on every visit. - The kit names the layout once, in the
layoutcallback ofcreateInertiaApp, and Inertia keeps that instance. - Pass data with
defineOptions({ layout: { breadcrumbs } }); that object is merged onto the default layout.
An older Vue tutorial wraps every page in <AppLayout> inside the template. Inertia destroys that component on the next visit and creates another one. The sidebar scroll jumps back to the top. The Vue starter kit does not wrap the page. It names the layout once, and Inertia keeps that instance.
Do not add a second createInertiaApp. Do not wrap the page as well. The inner shell would still remount. The title callback in that same call is the document title guide. The stack is Laravel and Vue in 2026.
What the kit already chooses#
resources/js/app.ts already passes a layout function. Leave it.
layout: (name) => {
switch (true) {
case name === "Welcome":
return null;
case name.startsWith("auth/"):
return AuthLayout;
case name.startsWith("settings/"):
return [AppLayout, SettingsLayout];
default:
return AppLayout;
}
},| Page | Layout |
|---|---|
Welcome | none |
auth/* | AuthLayout |
settings/* | SettingsLayout inside AppLayout |
| everything else | AppLayout |
A component returned from the page replaces this function for that page only. The kit pages do not return one.
Breadcrumbs are props#
AppLayout already accepts breadcrumbs. A page can pass them and still use the function above:
defineOptions({
layout: { breadcrumbs: [{ title: "Posts", href: "/posts" }] },
});That object is not a component. Inertia merges it onto the default layout. The dashboard page in the kit does the same thing with its own crumbs.
Gotcha: props, not a component
Putting AppLayout in that option would replace the function in app.ts. Pass the props object only.
When the template still wraps the page#
Use this only on an app that does not already have the function above. Move the component out of the template.
Remounts every visit, then Persists:
<script setup lang="ts">
import AppLayout from "@/layouts/AppLayout.vue";
</script>
<template>
<AppLayout>
<h1>Posts</h1>
</AppLayout>
</template><script setup lang="ts">
import AppLayout from "@/layouts/AppLayout.vue";
defineOptions({ layout: AppLayout });
</script>
<template>
<h1>Posts</h1>
</template>Delete the <AppLayout> tags around the page. The template is only the slot. On the starter kit, skip this. The function in app.ts already selected the component.
Prove the layout persists
Scroll the sidebar halfway down, then click to another page that uses AppLayout. With a persistent layout, the sidebar stays where you left it.
Where this stops#
This page does not draw the sidebar, and it does not add a layout package. Settings already nest two layouts in the array above. The logged-in user inside that shell is the setup guide.
Recap#
- A layout in the page template is rebuilt on every visit; a layout chosen by Inertia persists.
- The starter kit picks layouts in one
layoutcallback; keep it. - Pass breadcrumbs with
defineOptions({ layout: { breadcrumbs } }). - On older apps, move the wrapper into
defineOptions({ layout: AppLayout }).
FAQ#
Why does my sidebar scroll reset on every Inertia visit?
The page wraps itself in the layout inside its template, so Inertia destroys and recreates it. Use a persistent layout instead.
Can a page use two layouts?
Yes. Return an array, like the kit does for settings: [AppLayout, SettingsLayout].
How do I pass breadcrumbs to the layout?
Use defineOptions({ layout: { breadcrumbs: [...] } }). Inertia merges that object onto the default layout as props.
Next steps#
- Set the Inertia document title in Vue: the other callback in the same
createInertiaApp. - Set up a Laravel + Vue app: the starter kit this builds on.
- Show a saved message in Vue: a toast that lives in the layout.
- Inertia docs: layouts



