Nuxt/docs/2.guide/2.directory-structure/1.layouts.md
2024-09-19 13:20:16 +01:00

181 lines
4.2 KiB
Markdown

---
title: "layouts"
head.title: "layouts/"
description: "Nuxt provides a layouts framework to extract common UI patterns into reusable layouts."
navigation.icon: i-ph-folder
---
::tip{icon="i-ph-rocket-launch" color="gray" }
For best performance, components placed in this directory will be automatically loaded via asynchronous import when used.
::
## Enable Layouts
Layouts are enabled by adding [`<NuxtLayout>`](/docs/api/components/nuxt-layout) to your [`app.vue`](/docs/guide/directory-structure/app):
```vue [app.vue]
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
```
To use a layout:
- Set a `layout` property in your page with [definePageMeta](/docs/api/utils/define-page-meta).
- Set the `name` prop of `<NuxtLayout>`.
::note
The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`.
::
::note
If no layout is specified, `layouts/default.vue` will be used.
::
::important
If you only have a single layout in your application, we recommend using [`app.vue`](/docs/guide/directory-structure/app) instead.
::
::important
Unlike other components, your layouts must have a single root element to allow Nuxt to apply transitions between layout changes - and this root element cannot be a `<slot />`.
::
## Default Layout
Add a `~/layouts/default.vue`:
```vue [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
```bash [Directory Structure]
-| layouts/
---| default.vue
---| custom.vue
```
Then you can use the `custom` layout in your page:
```vue twoslash [pages/about.vue]
<script setup lang="ts">
definePageMeta({
layout: 'custom'
})
</script>
```
::read-more{to="/docs/guide/directory-structure/pages#page-metadata"}
Learn more about `definePageMeta`.
::
You can directly override the default layout for all pages using the `name` property of [`<NuxtLayout>`](/docs/api/components/nuxt-layout):
```vue [app.vue]
<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`
:link-example{to="/docs/examples/features/layouts"}
## Changing the Layout Dynamically
You can also use the [`setPageLayout`](/docs/api/utils/set-page-layout) helper to change the layout dynamically:
```vue twoslash
<script setup lang="ts">
function enableCustomLayout () {
setPageLayout('custom')
}
definePageMeta({
layout: false,
});
</script>
<template>
<div>
<button @click="enableCustomLayout">Update layout</button>
</div>
</template>
```
:link-example{to="/docs/examples/features/layouts"}
## 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.
::code-group
```vue [pages/index.vue]
<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>
```
```vue [layouts/custom.vue]
<template>
<div>
<header>
<slot name="header">
Default header content
</slot>
</header>
<main>
<slot />
</main>
</div>
</template>
```
::
::important
If you use `<NuxtLayout>` within your pages, make sure it is not the root element (or [disable layout/page transitions](/docs/getting-started/transitions#disable-transitions)).
::