layouts
Enable Layouts
Layouts are enabled by adding <NuxtLayout> to your app.vue:
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
To use a layout:
- Set a
layoutproperty in your page with definePageMeta. - Set the
nameprop of<NuxtLayout>. - Set the
appLayoutproperty in route rules.
someLayout becomes some-layout.app/layouts/default.vue will be used.app.vue instead.<slot />.Default Layout
Add a ~/layouts/default.vue:
<template>
<div>
<p>Some default layout content shared across all pages</p>
<slot />
</div>
</template>
In a layout file, the content of the page will be displayed in the <slot /> component.
Named Layout
-| layouts/
---| default.vue
---| custom.vue
Then you can use the custom layout in your page:
<script setup lang="ts">
declare module 'nuxt/app' {
interface NuxtLayouts {
'custom': unknown
}
}
// ---cut---
definePageMeta({
layout: 'custom',
})
</script>
You can directly override the default layout for all pages using the name property of <NuxtLayout>:
<script setup lang="ts">
// You might choose this based on an API call or logged-in status
const layout = 'custom'
</script>
<template>
<NuxtLayout :name="layout">
<NuxtPage />
</NuxtLayout>
</template>
If you have a layout in nested directories, the layout's name will be based on its own path directory and filename, with duplicate segments being removed.
| File | Layout Name |
|---|---|
~/layouts/desktop/default.vue | desktop-default |
~/layouts/desktop-base/base.vue | desktop-base |
~/layouts/desktop/index.vue | desktop |
For clarity, we recommend that the layout's filename matches its name:
| File | Layout Name |
|---|---|
~/layouts/desktop/DesktopDefault.vue | desktop-default |
~/layouts/desktop-base/DesktopBase.vue | desktop-base |
~/layouts/desktop/Desktop.vue | desktop |
Changing the Layout Dynamically
You can also use the setPageLayout helper to change the layout dynamically:
<script setup lang="ts">
declare module 'nuxt/app' {
interface NuxtLayouts {
'custom': unknown
}
}
// ---cut---
function enableCustomLayout () {
setPageLayout('custom')
}
definePageMeta({
layout: false,
})
</script>
<template>
<div>
<button @click="enableCustomLayout">
Update layout
</button>
</div>
</template>
You can also set layouts for specific routes using the appLayout property in route rules:
export default defineNuxtConfig({
routeRules: {
// Set layout for specific route
'/admin': { appLayout: 'admin' },
// Set layout for multiple routes
'/dashboard/**': { appLayout: 'dashboard' },
// Disable layout for a route
'/landing': { appLayout: false },
},
})
Passing Props to Layouts
You can pass props to layouts in several ways.
Via definePageMeta
Use the object syntax for the layout property to pass props directly from your page:
<script setup lang="ts">
definePageMeta({
layout: {
name: 'panel',
props: {
sidebar: true,
title: 'Dashboard',
},
},
})
</script>
<script setup lang="ts">
const props = defineProps<{
sidebar?: boolean
title?: string
}>()
</script>
<template>
<div>
<aside v-if="sidebar">
Sidebar
</aside>
<main>
<h1>{{ title }}</h1>
<slot />
</main>
</div>
</template>
defineProps. You'll get autocomplete and type-checking in your editor.Via setPageLayout
You can also pass props when changing the layout dynamically with setPageLayout:
setPageLayout('panel', { sidebar: true, title: 'Dashboard' })
Overriding a Layout on a Per-page Basis
If you are using pages, you can take full control by setting layout: false and then using the <NuxtLayout> component within the page.
<script setup lang="ts">
definePageMeta({
layout: false,
})
</script>
<template>
<div>
<NuxtLayout name="custom">
<template #header>
Some header template content.
</template>
The rest of the page
</NuxtLayout>
</div>
</template>
<template>
<div>
<header>
<slot name="header">
Default header content
</slot>
</header>
<main>
<slot />
</main>
</div>
</template>
<NuxtLayout> within your pages, make sure it is not the root element (or disable layout/page transitions).