Skip to main contentSkip to docs navigation

Loading indicator with border and growing variants, sized and colored via props, and built-in status role and screen-reader label.

Overview

<Spinner> renders a loading indicator that animates with CSS alone once mounted — no timers or animation library involved. It renders role="status" and a visually hidden label ("Loading...", overridable via visuallyHiddenLabel) automatically, so a spinner is announced to assistive technology without any extra markup.

Loading...
JSX
import { Spinner } from '@chassis-ui/react'

export const Example = () => {
  return <Spinner />
}

Style variant

Set variant="grow" for a spinner that pulses in size instead of spinning; the default variant="border" renders a rotating ring.

Loading...
JSX
import { Spinner } from '@chassis-ui/react'

export const Example = () => {
  return <Spinner variant="grow" />
}

Colors

Set color to any Chassis context color to change the spinner's color, in either variant. The prop renders the spinner-{color} class of @chassis-ui/css; a spinner doesn't follow the text color around it.

Loading, default
Loading, alternate
Loading, primary
Loading, secondary
Loading, neutral
Loading, success
Loading, danger
Loading, warning
Loading, info
Loading, black
Loading, white
JSX
import { Spinner } from '@chassis-ui/react'
import { COLORS } from '../../utils'

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Spinner key={color} color={color} visuallyHiddenLabel={`Loading, ${color}`} />
      ))}
    </>
  )
}

Sizes

Set size="sm" for a smaller spinner sized to sit inline with compact UI, such as a button label; the default renders at the component's base size.

Loading...
Loading...
JSX
import { Spinner } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Spinner size="sm" />
      <Spinner size="sm" variant="grow" />
    </>
  )
}

In buttons

Nest a spinner inside a disabled <Button> to indicate that an action is in progress. Add aria-hidden="true" to the spinner once visible loading text is already present in the button, so assistive technology doesn't announce the loading state twice.

JSX
import { Button, Spinner } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Button disabled aria-label="Loading">
        <Spinner component="span" size="sm" aria-hidden="true" />
      </Button>
      <Button disabled>
        <Spinner component="span" size="sm" aria-hidden="true" />
        Loading...
      </Button>
    </>
  )
}
JSX
import { Button, Spinner } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Button disabled aria-label="Loading">
        <Spinner component="span" size="sm" variant="grow" aria-hidden="true" />
      </Button>
      <Button disabled>
        <Spinner component="span" size="sm" variant="grow" aria-hidden="true" />
        Loading...
      </Button>
    </>
  )
}

API

Spinner

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—
size?"sm"—
Renders a smaller spinner, with the spinner-sm class.
variant?"border" | "grow"—
Set the button variant to an outlined button or a ghost button.
visuallyHiddenLabel?string—
Set visually hidden label for accessibility purposes.