VibeUI
ComponentsDocs
VibeUI

Components with taste, that you own. Copy the source, retint the tokens, keep every line.

Library

  • All components
  • Signature pieces
  • Text effects
  • Footers

Docs

  • Introduction
  • Installation
  • Theming
  • CLI

Project

  • GitHub
  • Agents and MCP
  • Issues
  • MIT license
© 2026 VibeUI · MIT licensed
  1. Components
  2. Signature
  3. Orbit Ring

Orbit Ring

Labels circling a center point. Chips stay upright while the ring turns.

SignatureServer-safe
ReactTailwindA11yDarkMotion
Vibe

Install

bash
npx @agents-npm-packages/vibeui add orbit-ring --dir ./src/components/ui

Import

tsx
import { OrbitRing } from "@/components/ui/orbit-ring"

API

Generated from the component's TypeScript types, so it always matches the source. * marks a required prop.

<OrbitRing>

PropTypeDefaultDescription
items*{ id: string; label: string; }[]—The items to render.
centerReactNode—Content for the center of the ring.
radiusnumber104Ring radius in pixels.
classNamestring—Extra classes, merged with the component's own.

Source

src/components/ui/orbit-ring.tsx
import { cn } from "@/lib/utils";

/** Labels circling a center point. Chips stay upright while the ring turns. */
export function OrbitRing({
  items,
  center,
  radius = 104,
  className,
}: {
  items: { id: string; label: string }[];
  center?: React.ReactNode;
  radius?: number;
  className?: string;
}) {
  const size = radius * 2 + 80;

  return (
    <div
      className={cn("group/orbit relative mx-auto flex items-center justify-center", className)}
      style={{ width: size, height: size }}
    >
      <div
        aria-hidden
        className="absolute rounded-full border border-dashed border-line-strong"
        style={{ width: radius * 2, height: radius * 2 }}
      />
      <div className="absolute inset-0 animate-orbit group-hover/orbit:[animation-play-state:paused]">
        {items.map((item, i) => {
          const angle = (360 / items.length) * i;
          return (
            <span
              key={item.id}
              className="absolute left-1/2 top-1/2"
              style={{
                transform: `rotate(${angle}deg) translateY(-${radius}px) rotate(-${angle}deg)`,
              }}
            >
              <span className="block -translate-x-1/2 -translate-y-1/2 animate-orbit [animation-direction:reverse] group-hover/orbit:[animation-play-state:paused]">
                <span className="block rounded-full border border-line bg-surface px-3 py-1 text-xs font-medium text-ink shadow-quiet">
                  {item.label}
                </span>
              </span>
            </span>
          );
        })}
      </div>
      <div className="relative z-10 flex size-16 items-center justify-center rounded-full bg-ink text-center font-display text-lg text-surface shadow-lift">
        {center ?? "UI"}
      </div>
    </div>
  );
}

Exports OrbitRing. Peer dependencies: clsx, tailwind-merge.

PreviousOdometerNextPan Zoom