Octocat

Spinner

A component to display a loading state.

import { Spinner } from '@/components/spinner';

export default function SpinnerExample() {
  return <Spinner />;
}

Source Code

'use client';

import type { VariantProps } from 'cva';

import { cva } from '@/lib/utils/classnames';

const spinnerStyle = cva({
  base: [
    'relative',
    'animate-spin',
    'before:absolute before:top-0 before:left-0 before:block before:size-full before:rounded-full before:border-current before:opacity-40',
    'after:top-0 after:left-0 after:block after:size-full after:rounded-full after:border-transparent after:border-t-current after:border-r-current',
  ],
  variants: {
    size: {
      xs: 'size-2 before:border after:border',
      sm: 'size-3 before:border after:border',
      md: 'size-4 before:border-2 after:border-2',
      lg: 'size-5 before:border-2 after:border-2',
    },
  },
});

export interface SpinnerProps
  extends React.ComponentPropsWithRef<'div'>,
    VariantProps<typeof spinnerStyle> {}

const Spinner = ({ className, size = 'md', ...props }: SpinnerProps) => {
  return (
    <div
      aria-label="loading"
      role="progressbar"
      className={spinnerStyle({ size, className })}
      {...props}
    />
  );
};

export { Spinner };

API Reference

Extends the div element.

Prop Default Type
size md xssmmdlg

Examples

Sizes

import { Spinner } from '@/components/spinner';

export default function SpinnerSizesExample() {
  return (
    <div className="flex flex-col items-center gap-4">
      <Spinner size="xs" />
      <Spinner size="sm" />
      <Spinner size="md" />
      <Spinner size="lg" />
    </div>
  );
}

Color

import { Spinner } from '@/components/spinner';

export default function SpinnerColorExample() {
  return <Spinner className="text-emerald-500" />;
}

Best Practices

  1. Usage:

    • Use appropriate size for context
    • Consider using Skeleton for content loading
    • Maintain consistent colors with theme
  2. Accessibility:

    • Include aria-label for screen readers
    • Consider reduced motion preferences

Previous

Slider

Next

Switch