Nuxt uses the Transition
component under the hood to apply page transitions between the routes and layout transitions on the custom layouts.
Both page and layout transitions are applied using definePageMeta
utility function. You can add the pageTransition
key to the definePageMeta
of your page component to define a custom page transition for a specific route.
<script setup lang="ts">
definePageMeta({
pageTransition: {
name: 'fade-in'
}
})
</script>
When you apply a custom layout
to your page component using definePageMeta
, you can also add the layoutTransition
key to define a layout transition for that custom layout.
<script setup lang="ts">
definePageMeta({
layout: 'custom',
layoutTransition: {
name: 'slide-in'
}
})
</script>
::alert{type="warning"}
<NuxtPage />
and <NuxtLayout />
are already wrapped around Vue’s <Transition />
component and you do not need to add the <Transition>
component separately to your Nuxt pages or layouts.
::
Default name of pageTransition
is page
, while the default name of layoutTransition
is layout
.
You can create CSS transitions with the name of page
or layout
to activate default page and layout transition respectively. Then, define the global CSS in nuxt.config
.
::code-group
export default defineNuxtConfig({
css: [
// Global CSS
'@/assets/style/main.css',
]
})
/* Page transition */
.page-enter-active {
animation: slideIn .5s ease-out both;
}
.page-leave-active {
animation: slideOut .5s ease-in both;
}
@keyframes slideIn {
0% {
transform: translate3d(-100%, 0, 0);
}
100% {
transform: translate3d(0, 0, 0);
}
}
@keyframes slideOut {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(100%, 0, 0);
}
}
/* Layout transition */
.layout-enter-active {
animation: bounce-in 0.5s;
}
.layout-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
::
You can customize these default transition names globally using nuxt.config
. Both pageTransition
and layoutTransition
keys accept TransitionProps
as JSON serializable values where you can pass the name
, mode
and other valid transition-props of the custom CSS transition.
export default defineNuxtConfig({
pageTransition: {
name: 'fade',
mode: 'out-in' // default
},
layoutTransition: {
name: 'slide',
mode: 'out-in' // default
}
})
If you do modify the page Transition name
, you will also have to rename the CSS classes accordingly.
::alert{type="warning"}
These globally defined page and layout transitions can be overridden with definePageMeta
on an individual page.
::
definePageMeta
is used 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.
<script setup lang="ts">
definePageMeta({
pageTransition: {
name: 'bounce',
mode: 'out-in' // default
}
})
</script>
pageTransition
and layoutTransition
can be disabled for a specific route if required.
<script setup lang="ts">
definePageMeta({
pageTransition: false
layoutTransition: false
})
</script>
For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt routes.
This way presents perfect use-cases for JavaScript animation libraries such as GSAP or Tween.js.
<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 available in the Transition
component.
::
After disabling the default pageTransition: false
, you can apply dynamic transitions using conditional logic to assign dynamic transitions directly to to.meta.pageTransition
on your Nuxt pages.
This example also uses the pre-configured animation library, Animate.css.
::code-group
<script setup lang="ts">
const Router = useRouter()
onMounted(async () => {
Router.afterEach((to, from) => {
to.meta.pageTransition = +to.params.slug < +from.params.slug
? {
name: 'a',
mode: 'out-in',
appearActiveClass: "animate__animated animate__slideInRight",
enterActiveClass: "animate__animated animate__slideInRight",
leaveActiveClass: "animate__animated animate__slideOut",
duration: 500,
}
: {
name: 'a',
mode: 'out-in',
appearActiveClass: "animate__animated animate__slideInRight",
enterActiveClass: "animate__animated animate__slideInLeft",
leaveActiveClass: "animate__animated animate__slideOut",
duration: 500,
}
})
})
definePageMeta({
pageTransition: false,
})
</script>
export default defineNuxtConfig({
app: {
head: {
link: [
{
rel: "stylesheet",
href: "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
}
]
}
}
})
::
::alert{type="info"}
Learn more about additional props to customize transition classes in the Transition
component.
::
When <NuxtPage />
is used in app.vue
, transition-props can be passed directly as a component props to activate global transition.
<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.
::