This repository was archived by the owner on Apr 6, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1k
docs(getting-started): add transitions
page
#7987
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
3f470b8
docs(getting-started): add transitions page
Krutie c0ecf9b
docs(getting-started): add weblink to Vue transition
Krutie 14118cb
Merge branch 'main' into docs/getting-started-transitions
atinux 6216fe1
Update docs/content/1.getting-started/5.transitions.md
clemcode 2249dc3
Update docs/content/1.getting-started/5.transitions.md
clemcode e13c879
docs: big rewrite for clarity and videos
atinux c1037fd
update
atinux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,385 @@ | ||
--- | ||
navigation.icon: uil:moon-eclipse | ||
description: Nuxt leverages Vue's Transition component to apply transitions between pages and layouts. | ||
--- | ||
|
||
# Transitions | ||
|
||
Nuxt leverages Vue's [`<Transition>`](https://vuejs.org/guide/built-ins/transition.html#the-transition-component) component to apply transitions between pages and layouts. | ||
|
||
## Page transitions | ||
|
||
Nuxt sets `{ name: 'page', mode: 'out-in' }` transition by default for all your [pages](/guide/directory-structure/pages). | ||
|
||
To start adding transition between your pages, add the following CSS to your [`app.vue`](/guide/directory-structure/app): | ||
|
||
::code-group | ||
|
||
```html [app.vue] | ||
<template> | ||
<NuxtPage /> | ||
</template> | ||
|
||
<style> | ||
.page-enter-active, | ||
.page-leave-active { | ||
transition: all 0.4s; | ||
} | ||
.page-enter-from, | ||
.page-leave-to { | ||
opacity: 0; | ||
filter: blur(1rem); | ||
} | ||
</style> | ||
``` | ||
|
||
```html [pages/index.vue] | ||
<template> | ||
<div> | ||
<h1>Home page</h1> | ||
<NuxtLink to="/about">About page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
```html [pages/about.vue] | ||
<template> | ||
<div> | ||
<h1>About page</h1> | ||
<NuxtLink to="/">Home page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
This produces the following result when navigating between pages: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665061349/nuxt3/nuxt3-page-transitions_umwvmh.mp4" type="video/mp4"> | ||
</video> | ||
|
||
To set a different transition for a page, set the `pageTransition` key in [`definePageMeta`](/api/utils/define-page-meta) of the page: | ||
|
||
::code-group | ||
|
||
```vue [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'rotate' | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
```html [app.vue] | ||
<template> | ||
<NuxtPage /> | ||
</template> | ||
|
||
<style> | ||
/* ... */ | ||
.rotate-enter-active, | ||
.rotate-leave-active { | ||
transition: all 0.4s; | ||
} | ||
.rotate-enter-from, | ||
.rotate-leave-to { | ||
opacity: 0; | ||
transform: rotate3d(1, 1, 1, 15deg); | ||
} | ||
</style> | ||
``` | ||
|
||
:: | ||
|
||
Moving to the about page will add the 3d rotation effect: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665063233/nuxt3/nuxt3-page-transitions-cutom.mp4" type="video/mp4"> | ||
</video> | ||
|
||
## Layouts transitions | ||
|
||
Nuxt sets `{ name: 'layout', mode: 'out-in' }` transition by default for all your [layouts](/guide/directory-structure/layouts). | ||
|
||
To start adding transition between your pages, add the following CSS to your [`app.vue`](/guide/directory-structure/app): | ||
|
||
::code-group | ||
|
||
```html [app.vue] | ||
<template> | ||
<NuxtLayout> | ||
<NuxtPage /> | ||
</NuxtLayout> | ||
</template> | ||
|
||
<style> | ||
.layout-enter-active, | ||
.layout-leave-active { | ||
transition: all 0.4s; | ||
} | ||
.layout-enter-from, | ||
.layout-leave-to { | ||
filter: grayscale(1); | ||
} | ||
</style> | ||
``` | ||
|
||
```html [layouts/default.vue] | ||
<template> | ||
<div> | ||
<pre>default layout</pre> | ||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
div { | ||
background-color: lightgreen; | ||
} | ||
</style> | ||
``` | ||
|
||
```html [layouts/orange.vue] | ||
<template> | ||
<div> | ||
<pre>orange layout</pre> | ||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
div { | ||
background-color: #eebb90; | ||
padding: 20px; | ||
height: 100vh; | ||
} | ||
</style> | ||
``` | ||
|
||
```html [pages/index.vue] | ||
<template> | ||
<div> | ||
<h1>Home page</h1> | ||
<NuxtLink to="/about">About page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
```html [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
layout: 'orange' | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<h1>About page</h1> | ||
<NuxtLink to="/">Home page</NuxtLink> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
This produces the following result when navigating between pages: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665065289/nuxt3/nuxt3-layouts-transitions_c9hwlx.mp4" type="video/mp4"> | ||
</video> | ||
|
||
Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`: | ||
|
||
```vue [pages/about.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
layout: 'orange', | ||
layoutTransition: { | ||
name: 'slide-in' | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
## Global settings | ||
|
||
You can customize these default transition names globally using `nuxt.config`. | ||
|
||
Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components.html#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. | ||
|
||
```ts [nuxt.config.ts] | ||
export default defineNuxtConfig({ | ||
pageTransition: { | ||
name: 'fade', | ||
mode: 'out-in' // default | ||
}, | ||
layoutTransition: { | ||
name: 'slide', | ||
mode: 'out-in' // default | ||
} | ||
}) | ||
``` | ||
|
||
::alert{type="info"} | ||
If you change the `name` property, you also have to rename the CSS classes accordingly. | ||
:: | ||
|
||
To override the global transition property, use the `definePageMeta` to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in `nuxt.config` file. | ||
|
||
```vue [pages/some-page.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'bounce', | ||
mode: 'out-in' // default | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
## Disable Transitions | ||
|
||
`pageTransition` and `layoutTransition` can be disabled for a specific route: | ||
|
||
```vue [pages/some-page.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: false | ||
layoutTransition: false | ||
}) | ||
</script> | ||
``` | ||
|
||
Or globally in the `nuxt.config`: | ||
|
||
```ts [nuxt.config.ts] | ||
defineNuxtConfig({ | ||
pageTransition: false, | ||
layoutTransition: false | ||
}) | ||
``` | ||
|
||
## JavaScript Hooks | ||
|
||
For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages. | ||
|
||
This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://greensock.com/gsap/) or [Tween.js](https://createjs.com/tweenjs). | ||
|
||
```vue [pages/some-page.vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'custom-flip', | ||
mode: 'out-in', | ||
onBeforeEnter: (el) => { | ||
console.log('Before enter...') | ||
}, | ||
onEnter: (el, done) => {}, | ||
onAfterEnter: (el) => {} | ||
} | ||
}) | ||
</script> | ||
``` | ||
|
||
::alert{type="info"} | ||
Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) available in the `Transition` component. | ||
:: | ||
|
||
## Dynamic Transitions | ||
|
||
To apply dynamic transitions using conditional logic, you can leverage inline [middleware](/guide/directory-structure/middleware) to assign a different transition name to `to.meta.pageTransition`. | ||
|
||
::code-group | ||
|
||
```html [pages/[id].vue] | ||
<script setup lang="ts"> | ||
definePageMeta({ | ||
pageTransition: { | ||
name: 'slide-right', | ||
mode: 'out-in' | ||
}, | ||
middleware (to, from) { | ||
to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right' | ||
} | ||
}) | ||
</script> | ||
|
||
<template> | ||
<h1>#{{ $route.params.id }}</h1> | ||
</template> | ||
|
||
<style> | ||
.slide-left-enter-active, | ||
.slide-left-leave-active, | ||
.slide-right-enter-active, | ||
.slide-right-leave-active { | ||
transition: all 0.2s; | ||
} | ||
.slide-left-enter-from { | ||
opacity: 0; | ||
transform: translate(50px, 0); | ||
} | ||
.slide-left-leave-to { | ||
opacity: 0; | ||
transform: translate(-50px, 0); | ||
} | ||
.slide-right-enter-from { | ||
opacity: 0; | ||
transform: translate(-50px, 0); | ||
} | ||
.slide-right-leave-to { | ||
opacity: 0; | ||
transform: translate(50px, 0); | ||
} | ||
</style> | ||
``` | ||
|
||
```html [layouts/default.vue] | ||
<script setup lang="ts"> | ||
const route = useRoute() | ||
const id = computed(() => Number(route.params.id || 1)) | ||
const prev = computed(() => '/' + (id.value - 1)) | ||
const next = computed(() => '/' + (id.value + 1)) | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<slot /> | ||
<div v-if="$route.params.id"> | ||
<NuxtLink :to="prev">β¬ οΈ</NuxtLink> | | ||
<NuxtLink :to="next">β‘οΈ</NuxtLink> | ||
</div> | ||
</div> | ||
</template> | ||
``` | ||
|
||
:: | ||
|
||
The page now applies the `slide-left` transition when going to the next id and `slide-right` for the previous: | ||
|
||
<video controls class="rounded"> | ||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665069410/nuxt3/nuxt-dynamic-page-transitions.mp4" type="video/mp4"> | ||
</video> | ||
|
||
## Transition with NuxtPage | ||
|
||
When `<NuxtPage />` is used in `app.vue`, transition-props can be passed directly as a component props to activate global transition. | ||
|
||
```vue [app.vue] | ||
<template> | ||
<div> | ||
<NuxtPage :transition="{ | ||
name: 'bounce', | ||
mode: 'out-in' | ||
}" /> | ||
</NuxtLayout> | ||
</div> | ||
</template> | ||
``` | ||
|
||
::alert{type="warning"} | ||
Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. | ||
:: |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.