NEW
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
Learn more
Skip to content
Docs

Orbiting Items

List component with orbiting items. The items orbit around the center of the list.

Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/list/orbiting-items.json

Manual

Add to your CSS

@keyframes rotate-full {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

Run the following command

It will create a new file orbiting-items.tsx inside the components/animata/list directory.

mkdir -p components/animata/list && touch components/animata/list/orbiting-items.tsx

Paste the code

Open the newly created file and paste the following code:

import { Icons } from "@/components/icons";
import { cn } from "@/lib/utils";
 
export const testOrbitingItems = [
  <Icons.gitHub key="github" className="h-6 w-6 text-black" />,
  <Icons.twitter key="twitter" className="h-6 w-6 text-black" />,
  <Icons.react key="yarn" className="h-6 w-6 text-black" />,
  <Icons.tailwind key="tailwind" className="h-6 w-6 text-black" />,
  <Icons.framerMotion key="framer" className="h-6 w-6 text-black" />,
  <Icons.apple key="apple" className="h-6 w-6 text-black" />,
];
 
interface OrbitingItemsProps {
  /**
   * The radius of the circle in percentage, relative to the container.
   */
  radius: number;
 
  /**
   * The items to orbit around the center of the parent element.
   */
  items: React.ReactNode[];
 
  /**
   * Pause the animation when the parent element is hovered.
   */
  pauseOnHover?: boolean;
 
  /**
   * Class name for the background element.
   */
  backgroundClassName?: string;
 
  /**
   * Class name for the container element.
   */
  containerClassName?: string;
 
  /**
   * Additional classes for the item container.
   */
  className?: string;
}
 
const calculateItemStyle = ({
  index,
  radius,
  totalItems,
}: {
  radius: number;
  index: number;
  totalItems: number;
}) => {
  const angle = (index / totalItems) * 360;
  const radians = (angle * Math.PI) / 180;
  const x = radius * Math.cos(radians);
  const y = radius * Math.sin(radians);
  return {
    left: `${50 + x}%`,
    top: `${50 + y}%`,
    transform: "translate(-50%, -50%)",
  };
};
 
export default function OrbitingItems({
  radius = 50,
  items = testOrbitingItems,
  pauseOnHover,
  backgroundClassName,
  containerClassName,
  className,
}: OrbitingItemsProps) {
  // The idea is to distribute the items in a circle around the center of the parent element.
  // Then the whole parent element rotates around its center.
  // The items rotate in the opposite direction to the parent element so they appear to be stationary.
 
  const reverse = cn(
    "animate-rotate-full transition-transform ease-linear direction-reverse repeat-infinite",
    {
      "group-hover/orbit:[animation-play-state:paused]": pauseOnHover,
    },
  );
 
  return (
    <div
      className={cn(
        "full-content group/orbit flex items-center justify-center py-32",
        containerClassName,
      )}
    >
      <div
        className={cn(
          "absolute inset-0 h-full w-full items-center [background:radial-gradient(125%_125%_at_50%_10%,#030637_30%,#10439F_100%)]",
          backgroundClassName,
        )}
      />
      <div
        className={cn(
          "relative flex h-64 w-64 animate-rotate-full items-center justify-center ease-linear repeat-infinite",
          {
            "group-hover/orbit:[animation-play-state:paused]": pauseOnHover,
          },
          className,
        )}
      >
        <div className="absolute h-full w-full rounded-full border-2 border-gray-500" />
        {items.map((item, index) => {
          return (
            <div
              key={index}
              className="absolute flex h-12 w-12 items-center justify-center rounded-full bg-gray-200"
              style={calculateItemStyle({
                index,
                radius,
                totalItems: items.length,
              })}
            >
              <div className={reverse}>{item}</div>
            </div>
          );
        })}
 
        <div
          className={cn("absolute h-1/2 w-1/2 rounded-full border-2 border-gray-700", reverse)}
        />
      </div>
    </div>
  );
}

Credits

Built by hari