Posts

Build a Custom Motion Background in NextJs

Introduction

This article demonstates how to create a background animation which run across routes.

Prerequisite

Base NextJs, CSS and Typescript knowledge.

Breadkdown

Step 1: Create a new NextJs project

We're going to use bun to create our new project. For more information, check out bun.sh.

bun create next-app # Initialize a NextJs app with create-next-app and choose all the default options.
cd my-app
bun --bun run dev

Step 2: Setup our background component

First, we need to create a background component that wraps all the pages for which we wish to have the motion background.
Create a components directory and add Motion.tsx under the components folder.

app/
├── component/
│   └── Motion.tsx
├── layout.tsx
└── page.tsx

Then, setup the Motion.tsx.

'use client'
import React from 'react'
import { usePathname } from 'next/navigation'
import './motion.css'

export default function Motion({ children }: { children: React.ReactNode }) {
  const pathname = usePathname()

  React.useEffect(() => {
    const bgCircle = document.getElementById('bgcircle')
  }, [pathname])

  return (
    <div className="overflow-x-clip overflow-y-hidden relative h-screen font-mono">
      <div
        id="bgcircle"
        style={{
          width: 554.69,
          height: 520.02,
          transform: 'rotate(-13.48deg)',
          transformOrigin: '0 0',
          background:
            'linear-gradient(162deg, #DDFFFF 0%, rgba(84.93, 183.45, 254.79, 0.94) 70%, rgba(34, 56.10, 255, 0.94) 100%)',
          boxShadow: '0px 10px 180px #E1CDFA',
          borderRadius: 9999,
          zIndex: -1,
        }}
        className="absolute -top-[5%] -left-[10%] max-w-[100vw]"
      />

      {children}
    </div>
  )
}

React.useEffect will be called whenever the dependency i.e. pathname is changed.

We setup a background with position absolute so that it does not messup the position of other components.
After setting up the component, we need to update it's position when navigating across the routes.

 React.useEffect(() => {
   const bgCircle = document.getElementById('bgcircle')
+  if (pathname === '/') {
+    bgCircle.style.top = '-5%'
+    bgCircle.style.left = '-10%'
+  } else if (pathname.startsWith('/blog/')) {
+    bgCircle.style.top = '-150%'
+    bgCircle.style.left = '-150%'
+  }
 }, [pathname])

To make the transition smooth, we can customize the motion.css.

/* app/components/motion.css */
div {
  transition: all 0.5s ease-in-out;
}

Step 3: Wrap the app inside the Motion component

After setting up the component, we need to wrap our entire app inside this background privider.

// app/layout.tsx
+import Motion from '@/app/components/Motion'

@@ -- @@

 export default function RootLayout({
   children,
 }: {
   children: React.ReactNode
 }) {
   return (
     <html lang="en">
       <body>
-        {children}
+        <Motion>{children}</Motion>
       </body>
     </html>
   )
 }

And now, the entire app is wrapped with our Motion component.
Create /blog/ routes and observe the change of our new background!!