Skip to main content

Aceternity UI vs Magic UI vs shadcn/ui: Animated React Components 2026

·PkgPulse Team

Aceternity UI vs Magic UI vs shadcn/ui: Animated React Components in 2026

TL;DR

All three use the copy-paste philosophy — you don't install a package, you copy components into your codebase. Aceternity UI specializes in stunning visual effects (3D cards, glowing beams, magnetic buttons, particle backgrounds) that make landing pages pop. Magic UI focuses on polished micro-interactions and marketing animations (animated beams, retro grids, neon gradients). shadcn/ui is the most practical — clean, accessible components with optional animation via Framer Motion, primarily built for application UIs. For marketing pages: Aceternity or Magic UI. For application UIs: shadcn/ui.

Key Takeaways

  • All three are copy-paste — no npm package to install, you own the code
  • Aceternity UI GitHub stars: ~28k — the visual effects leader, heavily used in SaaS landing pages
  • Magic UI GitHub stars: ~15k — growing fast, especially popular in developer-focused products
  • shadcn/ui GitHub stars: ~85k — the most popular overall, used in enterprise React apps
  • All use Tailwind CSSclass-variance-authority and tailwind-merge are standard dependencies
  • Framer Motion is the animation engine for all three — npm install framer-motion
  • Aceternity uses Three.js for 3D effects — heavier dependency but enables GPU-accelerated visuals

The Copy-Paste Component Revolution

The copy-paste approach flipped the traditional library model. Instead of importing from @acme/ui, you:

  1. Browse the component library website
  2. Click "Copy code" on the component you want
  3. Paste into your components/ui/ folder
  4. Customize freely — it's your code now

This approach won because:

  • No version upgrades breaking your code
  • Full control over animations, colors, and behavior
  • Bundle includes only what you use
  • Components adapt to your design system, not the other way around

Aceternity UI: Visual Spectacle for Landing Pages

Aceternity specializes in eye-catching effects. Their hero sections, cards, and backgrounds are designed to make visitors stop scrolling.

Installation Prerequisites

npm install framer-motion clsx tailwind-merge
# Some components also need:
npm install three @types/three    # 3D Globe, Vortex
npm install react-icons           # Some icon dependencies

3D Card Effect

// Copy from ui.aceternity.com/components/3d-card-effect
"use client";

import { CardContainer, CardBody, CardItem } from "@/components/ui/3d-card";

export function FeatureCard() {
  return (
    <CardContainer className="inter-var">
      <CardBody className="bg-gray-50 relative group/card dark:hover:shadow-2xl dark:hover:shadow-emerald-500/[0.1] dark:bg-black dark:border-white/[0.2] border-black/[0.1] w-auto sm:w-[30rem] h-auto rounded-xl p-6 border">
        <CardItem
          translateZ="50"
          className="text-xl font-bold text-neutral-600 dark:text-white"
        >
          Make things float in air
        </CardItem>
        <CardItem
          as="p"
          translateZ="60"
          className="text-neutral-500 text-sm max-w-sm mt-2 dark:text-neutral-300"
        >
          Hover over this card to unleash the power of CSS perspective.
        </CardItem>
        <CardItem translateZ={100} className="w-full mt-4">
          <img
            src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e"
            className="h-60 w-full object-cover rounded-xl"
            alt="thumbnail"
          />
        </CardItem>
        <div className="flex justify-between items-center mt-20">
          <CardItem
            translateZ={20}
            as="a"
            href="#"
            className="px-4 py-2 rounded-xl text-xs font-normal dark:text-white"
          >
            Try now →
          </CardItem>
          <CardItem
            translateZ={20}
            as="button"
            className="px-4 py-2 rounded-xl bg-black dark:bg-white dark:text-black text-white text-xs font-bold"
          >
            Sign up
          </CardItem>
        </div>
      </CardBody>
    </CardContainer>
  );
}
// Spotlight with mouse tracking — the iconic Aceternity effect
"use client";

import { useRef, useState } from "react";
import { motion } from "framer-motion";

interface SpotlightProps {
  className?: string;
  fill?: string;
}

export function Spotlight({ className = "", fill = "white" }: SpotlightProps) {
  return (
    <svg
      className={`animate-spotlight pointer-events-none absolute z-[1] h-[169%] w-[138%] lg:w-[84%] opacity-0 ${className}`}
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 3787 2842"
      fill="none"
    >
      <g filter="url(#filter)">
        <ellipse
          cx="1924.71"
          cy="273.501"
          rx="1924.71"
          ry="273.501"
          transform="matrix(-0.822377 -0.568943 -0.568943 0.822377 3631.88 2291.09)"
          fill={fill}
          fillOpacity="0.21"
        />
      </g>
      <defs>
        <filter id="filter">
          <feGaussianBlur stdDeviation="151" result="effect1_foregroundBlur" />
        </filter>
      </defs>
    </svg>
  );
}

// Usage in hero
export function HeroSection() {
  return (
    <div className="relative min-h-screen flex items-center justify-center bg-black overflow-hidden">
      <Spotlight
        className="-top-40 left-0 md:left-60 md:-top-20"
        fill="white"
      />
      <div className="relative z-10 text-center">
        <h1 className="text-4xl font-bold text-white">
          Ship faster with AI
        </h1>
      </div>
    </div>
  );
}

Background Beams (Signature Effect)

// BackgroundBeams — complex SVG animation that runs on CSS
"use client";

export function BackgroundBeams({ className }: { className?: string }) {
  // 20 animated SVG paths with gradient fills
  // Each has staggered animation delays
  return (
    <div className={`absolute inset-0 overflow-hidden ${className}`}>
      <svg
        className="absolute [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)] inset-0 h-full w-full stroke-neutral-200/50 [stroke-dasharray:6] [stroke-dashoffset:6] animate-beam"
        aria-hidden="true"
      >
        {/* Multiple animated path elements */}
        {Array.from({ length: 20 }).map((_, i) => (
          <path
            key={i}
            d={`M${-380 + i * 40} -189C${-380 + i * 40} -189 ...`}
            strokeWidth="0.5"
            style={{ animationDelay: `${i * 0.2}s` }}
          />
        ))}
      </svg>
    </div>
  );
}

Magic UI: Polished Micro-Interactions

Magic UI focuses on components that feel magical in subtle ways — animated counters, beam animations, border gradients, shine effects.

Installation Prerequisites

npm install framer-motion clsx tailwind-merge

Animated Beam (Connecting Elements)

// Magic UI's signature component — animated connection lines
"use client";

import { AnimatedBeam } from "@/components/magicui/animated-beam";
import { useRef } from "react";

export function OrbitingCirclesDemo() {
  const containerRef = useRef<HTMLDivElement>(null);
  const div1Ref = useRef<HTMLDivElement>(null);
  const div2Ref = useRef<HTMLDivElement>(null);

  return (
    <div
      className="relative flex w-full max-w-[500px] items-center justify-center overflow-hidden rounded-lg bg-background"
      ref={containerRef}
    >
      <div className="flex size-full flex-col items-stretch justify-between gap-10">
        <div className="flex flex-row justify-between">
          <div ref={div1Ref} className="z-10 flex items-center justify-center rounded-full border-2 p-3">
            <img src="/logos/openai.svg" className="h-6 w-6" />
          </div>
          <div ref={div2Ref} className="z-10 flex items-center justify-center rounded-full border-2 p-3">
            <img src="/logos/anthropic.svg" className="h-6 w-6" />
          </div>
        </div>
      </div>

      <AnimatedBeam
        containerRef={containerRef}
        fromRef={div1Ref}
        toRef={div2Ref}
        curvature={-75}
        endYOffset={-10}
      />
    </div>
  );
}

Shimmer Button

// ShimmerButton — subtle animated CTA
"use client";

import { cn } from "@/lib/utils";
import React, { CSSProperties } from "react";

interface ShimmerButtonProps {
  shimmerColor?: string;
  shimmerSize?: string;
  borderRadius?: string;
  shimmerDuration?: string;
  background?: string;
  className?: string;
  children?: React.ReactNode;
  onClick?: () => void;
}

export const ShimmerButton = ({
  shimmerColor = "#ffffff",
  shimmerSize = "0.05em",
  shimmerDuration = "3s",
  borderRadius = "100px",
  background = "rgba(0, 0, 0, 1)",
  className,
  children,
  onClick,
}: ShimmerButtonProps) => {
  return (
    <button
      onClick={onClick}
      style={
        {
          "--spread": "90deg",
          "--shimmer-color": shimmerColor,
          "--radius": borderRadius,
          "--speed": shimmerDuration,
          "--cut": shimmerSize,
          "--bg": background,
        } as CSSProperties
      }
      className={cn(
        "group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)]",
        className
      )}
    >
      <div
        className={cn(
          "-z-30 blur-[2px]",
          "absolute inset-0 overflow-visible [container-type:size]",
          "before:absolute before:inset-0 before:aspect-square before:w-full before:opacity-0 before:[background:conic-gradient(from_0deg,transparent_0_340deg,white_360deg)] before:[rotate:0deg] before:[translate:0_0] group-hover:before:opacity-100 group-hover:before:[animation:spin_var(--speed)_linear_infinite]"
        )}
      />
      <div className="absolute inset-[calc(var(--cut))] rounded-[calc(var(--radius)-var(--cut))] [background:var(--bg)]" />
      <span className="z-10 text-sm font-medium tracking-wide">{children}</span>
    </button>
  );
};

Number Ticker (Animated Stats)

// NumberTicker — count up animation for metrics
import { useEffect, useRef } from "react";
import { useInView, useMotionValue, useSpring } from "framer-motion";

function useNumberTicker(value: number) {
  const ref = useRef<HTMLSpanElement>(null);
  const motionValue = useMotionValue(0);
  const springValue = useSpring(motionValue, { duration: 3000 });
  const isInView = useInView(ref, { once: true, margin: "0px" });

  useEffect(() => {
    if (isInView) motionValue.set(value);
  }, [motionValue, isInView, value]);

  useEffect(() => {
    return springValue.on("change", (latest) => {
      if (ref.current) {
        ref.current.textContent = Intl.NumberFormat("en-US").format(
          Math.round(latest)
        );
      }
    });
  }, [springValue]);

  return ref;
}

export function NumberTicker({ value }: { value: number }) {
  const ref = useNumberTicker(value);
  return (
    <span
      className="inline-block tabular-nums text-black dark:text-white tracking-tighter"
      ref={ref}
    />
  );
}

// Usage on stats page
<div className="text-5xl font-bold">
  <NumberTicker value={1500000} />
  <span className="text-gray-500">+ installs</span>
</div>

shadcn/ui: The Application Foundation

shadcn/ui provides 60+ accessible components (Dialog, Select, Combobox, Calendar, etc.) built on Radix UI primitives. Animation is available but secondary to function and accessibility.

Installation

npx shadcn@latest init
npx shadcn@latest add button card dialog select

Animated Components

// shadcn/ui uses framer-motion for modal transitions
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";

// Dialog has built-in slide/fade animation via Radix UI
export function DeleteConfirmDialog({ onConfirm }: { onConfirm: () => void }) {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="destructive">Delete Account</Button>
      </DialogTrigger>
      <DialogContent>  {/* Animated in with CSS keyframes */}
        <DialogHeader>
          <DialogTitle>Are you absolutely sure?</DialogTitle>
          <DialogDescription>
            This action cannot be undone.
          </DialogDescription>
        </DialogHeader>
        <div className="flex gap-3 justify-end mt-4">
          <Button variant="outline">Cancel</Button>
          <Button variant="destructive" onClick={onConfirm}>
            Yes, delete my account
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  );
}

Adding Framer Motion to shadcn Components

// Extend shadcn/ui with custom Framer Motion animations
import { motion, AnimatePresence } from "framer-motion";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

interface AnimatedCardProps {
  title: string;
  children: React.ReactNode;
  index: number;
}

export function AnimatedCard({ title, children, index }: AnimatedCardProps) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ delay: index * 0.1, duration: 0.4 }}
    >
      <Card>
        <CardHeader>
          <CardTitle>{title}</CardTitle>
        </CardHeader>
        <CardContent>{children}</CardContent>
      </Card>
    </motion.div>
  );
}

Feature Comparison

FeatureAceternity UIMagic UIshadcn/ui
Distribution modelCopy-pasteCopy-pasteCopy-paste (CLI)
Animation focusHeavy (3D, particles)Medium (micro-interactions)Light (transitions)
AccessibilityBasicBasic✅ Radix UI
Form components✅ Full suite
Tailwind required
Framer MotionRequiredRequiredOptional
Three.jsSome components
Best forLanding pagesMarketing sitesApplication UIs
Component count80+50+60+
TypeScript
Dark mode
CLI installer✅ (shadcn add)
GitHub stars28k15k85k

When to Use Each

Choose Aceternity UI if:

  • You're building a SaaS landing page and need to impress in the first 3 seconds
  • 3D card effects, spotlight animations, and particle backgrounds are part of your design
  • You're okay with heavier dependencies (Three.js for some components)
  • The aesthetic is appropriate (dark mode, neon/glow effects)

Choose Magic UI if:

  • You need polished micro-interactions (animated beam connectors, shimmer buttons, number tickers)
  • Your site is developer-focused or technical (common in DevTool marketing)
  • You want the copy-paste approach but with a lighter aesthetic than Aceternity
  • Animated statistics and metrics displays are important

Choose shadcn/ui if:

  • You're building an application UI (dashboards, admin panels, SaaS apps)
  • Accessibility matters (Radix UI primitives)
  • You need form components, date pickers, comboboxes, and data tables
  • You want animations that enhance UX without overwhelming it

Combine all three: Many production projects use shadcn/ui for the app shell and forms, Aceternity or Magic UI for landing pages and marketing sections. They all use the same Tailwind + Framer Motion stack, so combining is straightforward.


Methodology

Data sourced from GitHub repositories (star counts as of February 2026), component documentation, and community usage patterns. All code examples verified against current library versions.


Related: shadcn/ui vs Radix UI for headless vs styled comparisons, or DaisyUI vs Flowbite vs NextUI for Tailwind component libraries.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.