Loader

Animated spinner used internally by Button when loading. Can also be used standalone.

API Reference

PropTypeDefault
size"xs" | "sm" | "md" | "lg" | "xl""md"
color"root" | "primary" | "secondary""root"
aria-labelstring"Loading"

Sizes

<Loader size="xs" />
<Loader size="sm" />
<Loader size="md" />
<Loader size="lg" />
<Loader size="xl" />

Colors

<Loader color="root" />
<Loader color="primary" />
<Loader color="secondary" />

Basic Usage

import { Loader } from "@/ui";

<Loader />

Source

src/ui/Loader.tsx
import { cn } from "@/utils";

interface LoaderProps {
  size?: "xs" | "sm" | "md" | "lg" | "xl";
  color?: "root" | "primary" | "secondary";
  className?: string;
  "aria-label"?: string;
}

const sizeClass = {
  xs: "size-3",
  sm: "size-3.5",
  md: "size-4",
  lg: "size-5",
  xl: "size-6",
} as const;

const colorClass = {
  root: "text-root-contrast",
  primary: "text-primary",
  secondary: "text-secondary",
} as const;

export function Loader({
  size = "md",
  color = "root",
  className,
  "aria-label": ariaLabel = "Loading",
}: LoaderProps) {
  return (
    <svg
      className={cn(
        "shrink-0 animate-spin",
        sizeClass[size],
        colorClass[color],
        className,
      )}
      viewBox="0 0 24 24"
      fill="none"
      role="status"
      aria-label={ariaLabel}
    >
      <circle
        className="opacity-25"
        cx="12"
        cy="12"
        r="10"
        stroke="currentColor"
        strokeWidth="4"
      />
      <path
        className="opacity-75"
        fill="currentColor"
        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
      />
    </svg>
  );
}