Studio KitLoaders and Feedbackno dependencies

OrbitLoader

A compact loader with two counter-rotating orbit rings carrying satellites around a softly breathing accent core, implemented with CSS keyframes.

Preview

Customize

4 props
72
1.4

Installation

Copies the component source and its CSS Module into your project.

npx motionfoundry add orbit-loader

Writes components/ui/orbit-loader.tsx and components/styles/orbit-loader.module.css.

Usage

Updates live as you change the controls — only props that differ from the defaults are included.

example.tsx
1import { OrbitLoader } from "@motionfoundry/ui";2 3export function Example() {4  return (5    <OrbitLoader />6  );7}

Props

PropTypeDefault
size

Loader diameter in pixels.

number72
duration

Outer orbit period in seconds; the inner ring runs at twice this, reversed.

number1.4
color

Accent color for the core and leading satellite.

string'#38bdf8'
label

Accessible label exposed via aria-label on the status element.

string'Loading'
className

Additional class merged onto the root element.

string''

Accessibility

Root uses role="status" with an aria-label (default 'Loading'); all visual parts are aria-hidden. Under prefers-reduced-motion rotation and breathing stop, leaving a static orbit composition.

Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.

Source

components/ui/orbit-loader.tsx
1"use client";2 3import * as React from "react";4import styles from "../styles/orbit-loader.module.css";5 6export interface OrbitLoaderProps {7  /** Loader diameter in pixels */8  size?: number;9  /** Outer orbit period in seconds (inner orbit runs at twice this, reversed) */10  duration?: number;11  /** Accent color for the core and leading satellite */12  color?: string;13  /** Accessible label announced by assistive technology */14  label?: string;15  /** Optional className merged onto the root */16  className?: string;17}18 19export function OrbitLoader({20  size = 72,21  duration = 1.4,22  color = "#38bdf8",23  label = "Loading",24  className = "",25}: OrbitLoaderProps) {26  const styleVars = {27    "--mf-ol-size": `${size}px`,28    "--mf-ol-duration": `${duration > 0 ? duration : 1.4}s`,29    "--mf-ol-color": color,30  } as React.CSSProperties;31 32  return (33    <div role="status" aria-label={label} style={styleVars} className={`${styles.root} ${className}`.trim()}>34      <span aria-hidden="true" className={styles.core} />35      <span aria-hidden="true" className={`${styles.ring} ${styles.outer}`}>36        <span className={`${styles.dot} ${styles.accentDot}`} />37      </span>38      <span aria-hidden="true" className={`${styles.ring} ${styles.inner}`}>39        <span className={styles.dot} />40      </span>41    </div>42  );43}