# Bars Spinner

Twelve bars around a hub fading in turn, announced as Loading. No JavaScript.

Docs: https://corsairui.vercel.app/docs/bars-spinner

## Install

```bash
pnpm dlx shadcn@latest add @corsair-ui/bars-spinner
```

Also adds: `utils`.
npm: `clsx`, `tailwind-merge`.

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `number \| string` |  | Width and height; or use a size-* class. |

## Styling

Restyle it in the project that installs it: `className` on each part, the theme variables, and these attributes with arbitrary variants (`[&_[data-slot=…]]:…`, `data-[state=…]:…`).

data-slot: `bars-spinner`

## Accessibility

- It is role="status", announced as "Loading". Pass a specific aria-label when you can.
- With prefers-reduced-motion it turns at half speed rather than stopping.

## Examples

On the docs page: Sizes and colours, In a button. The usage examples in the source comments below are the reference.

## Source

What `shadcn add` writes into the project:

### bars-spinner.tsx

```tsx
import type { ComponentProps, CSSProperties } from "react";

import { cn } from "@/registry/default/lib/utils";

const BARS = Array.from({ length: 12 }, (_, index) => index);

interface BarsSpinnerProps extends ComponentProps<"span"> {
  /** Width and height, as a CSS length or a number of px. Or size it with a `size-*` class. */
  size?: number | string;
}

/**
 * Twelve bars around a hub, fading one after another. It takes the current
 * text colour and is announced as "Loading"; pass a more specific
 * `aria-label` when you can ("Syncing charts"). With `prefers-reduced-motion`
 * it turns at half speed rather than stopping, since it reports progress.
 * No JavaScript: it works in server components.
 */
function BarsSpinner({ size, className, style, ...props }: BarsSpinnerProps) {
  return (
    <span
      role="status"
      aria-label="Loading"
      data-slot="bars-spinner"
      className={cn(
        "relative inline-block size-4 shrink-0 [--bars-spinner-period:1s] motion-reduce:[--bars-spinner-period:2s]",
        className
      )}
      style={{ ...(size === undefined ? null : { width: size, height: size }), ...style }}
      {...props}
    >
      {BARS.map((index) => (
        <span
          key={index}
          aria-hidden="true"
          className="animate-bars-spinner absolute top-[45.5%] left-[37%] h-[9%] w-[26%] rounded-full bg-current"
          style={
            {
              transform: `rotate(${index * 30}deg) translate(140%)`,
              animationDuration: "var(--bars-spinner-period)",
              // Negative delays start every bar part-way through, so the wheel turns from the first frame.
              animationDelay: `calc(var(--bars-spinner-period) * ${(index - 12) / 12})`,
            } as CSSProperties
          }
        />
      ))}
    </span>
  );
}

export { BarsSpinner, type BarsSpinnerProps };
```
