All guides

Build an Animated Landing Page in Next.js with Tailwind and Motion

By Hizmedia · · 7 min read

A good landing page moves just enough to feel alive without slowing anyone down. This guide builds one in Next.js with the App Router, Tailwind CSS v4 and the Motion library: a hero, a features grid, social proof, pricing and a final call to action. Every section is a copy-paste component, so you own the code and can change anything.

1. Create the project

Start a new Next.js app. Say yes to TypeScript, Tailwind CSS and the App Router when it asks.

terminal
npx create-next-app@latest my-landing-page
cd my-landing-page
npm install motion

Motion is the only extra dependency. It's the animation library formerly known as Framer Motion, imported from motion/react.

2. Add components with the shadcn CLI

MotionKit components install with the shadcn CLI, which copies each file into your project and installs its dependencies. Run init once to create a components.json, then add what you need:

terminal
npx shadcn@latest init
npx shadcn@latest add https://www.motionkitui.com/r/marquee.json https://www.motionkitui.com/r/accordion.json

Files land in components/motionkit, so imports look like @/components/motionkit/marquee. Prefer to copy by hand? Every component page has the full source and a copy button.

3. Compose the page

Keep app/page.tsx as a Server Component and use the animated pieces inside it. Each MotionKit file starts with "use client", so only those parts ship JavaScript; your headings and copy render as plain HTML, which is fast and fully indexable.

app/page.tsx
import { Marquee } from "@/components/motionkit/marquee";
import { Accordion } from "@/components/motionkit/accordion";

export default function Page() {
  return (
    <main>
      <section className="px-6 py-24 text-center">
        <h1 className="text-5xl font-semibold tracking-tight">Ship pages that feel alive</h1>
        <p className="mt-4 text-lg text-neutral-400">Animated sections you paste in, tweak and ship.</p>
      </section>

      <Marquee fade>
        {["Northwind", "Lumen", "Arcadia", "Halcyon"].map((logo) => (
          <span key={logo} className="mx-8 text-xl font-semibold">{logo}</span>
        ))}
      </Marquee>

      <section className="mx-auto max-w-2xl px-6 py-24">
        <Accordion items={[{ id: "free", title: "Is there a free plan?", content: "Yes, and it never expires." }]} />
      </section>
    </main>
  );
}

For complete sections (an animated hero, a bento features grid, a scrolling testimonial wall and a pricing table with a billing switch), MotionKit Plus has ready-made ones, and the Page Builder exports a finished page.tsx from them.

4. Keep it fast

  • Animate transform and opacity. They run on the compositor and don't trigger layout; animating width, top or margin does.
  • Give animated sections their final size from the start, so nothing shifts as they animate in (this protects your Cumulative Layout Shift score).
  • Play entrance animations when content scrolls into view, not all at page load, and use once so they don't replay endlessly.
  • Pause canvas and requestAnimationFrame effects when they leave the screen. MotionKit's backgrounds already stop drawing off screen.
  • Keep the hero's headline as real text in the HTML, so the browser can paint it before any JavaScript runs.

5. Keep it accessible

Motion should never be the only way information arrives. Check four things before you ship: reduced motion removes large movement (see the reduced motion guide), every button and link works from the keyboard with a visible focus ring, text over animated backgrounds keeps at least 4.5:1 contrast, and anything that loops for more than five seconds can be paused.

6. Ship it

Push the repository to GitHub and import it into Vercel, or run npm run build and deploy the output anywhere that runs Node.js. Before launch, set a canonical URL for your domain, add a sitemap.xml and Open Graph images, and run Lighthouse on a throttled mobile profile, which is the closest thing to how most visitors will see it.