Spinner

A loading indicator, sized to match what is loading. For a value on a scale, use a Meter.

Installation

bun add @harmo-ui/css @harmo-ui/react

Usage

import { Spinner } from "@harmo-ui/react";

<Spinner size="large">Loading</Spinner>
<Spinner delay>Loading conversations</Spinner>

Examples

This site is using your theme

Sizes

Match the spinner to what is loading: data-size="small" (16px) inline and in table cells, the default (24px) for a section, and data-size="large" (40px) for a whole page or tab. On its own, each takes role="status" and is announced as "Loading".

LoadingLoadingLoading
<>
  <Spinner size="small">Loading</Spinner>
  <Spinner>Loading</Spinner>
  <Spinner size="large">Loading</Spinner>
</>

Delayed

data-delay keeps it hidden for 300ms, so quick loads never flash a spinner. Replay to watch it appear.

Loading
<Spinner delay>Loading</Spinner>

Inside a button

When the control's label already explains the wait, the spinner is aria-hidden, and the button draws it at 16px in its text color. Button covers loading states in full.

<Button loading>Saving changes</Button>

Custom size and color

--hspinner-size and --hspinner-stroke set the size and ring width, and the arc follows the element's color.

LoadingLoading
<>
  <Spinner
    style={
      { "--hspinner-size": "3.5rem", "--hspinner-stroke": "4px" } as CSSProperties
    }
  >
    Loading
  </Spinner>
  <Spinner style={{ color: "var(--harmo-green)" }}>Loading</Spinner>
</>

API reference

React

<Spinner> renders the spinner with role="status"; its children, which are required, are the label screen readers announce, such as "Loading". With aria-hidden="true", it's decorative and has neither. A Button's loading renders one for you. Other props are the <span>'s attributes.

PropEffect
sizesmall or large
delayKeeps it hidden for its first 300ms

HTML

A <span class="hspinner">. On its own, it takes role="status" and a visually hidden .hspinner-label; inside a control whose label explains the wait, aria-hidden="true". Load spinner.css. It needs no script: render it while something loads and remove it when done.

HookEffect
data-size="small"16px, for buttons, table cells, and inline
(default)24px, for a section while the rest of the page shows
data-size="large"40px with a 3px ring, for a whole page or tab
data-delayStays hidden for 300ms, so quick loads never flash a spinner
--hspinner-size, --hspinner-strokeThe size and the ring width
colorThe arc's color

See Spinner's full contract.

Accessibility

A standalone spinner takes role="status" with a visually hidden .hspinner-label, so screen readers announce what is loading. Inside a control whose label explains the wait, it is aria-hidden.