Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

docs(getting-started): add transitions page #7987

Merged
merged 7 commits into from Oct 6, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
385 changes: 385 additions & 0 deletions docs/content/1.getting-started/5.transitions.md
@@ -0,0 +1,385 @@
---
navigation.icon: uil:moon-eclipse
description: Nuxt leverages Vue's Transition component to apply transitions between pages and layouts.
---

# Transitions
clemcode marked this conversation as resolved.
Show resolved Hide resolved

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.
::