Spinner component is an animated icon that lets users know content or result of an action is being loaded.

Open in new tab
import { Spinner } from "@kesko/components";

export default () => <Spinner />;
import type { CSSProperties } from "react";
import { Spinner, Stack } from "@kesko/components";

export default () => (
  <Stack direction="row" gap="lg" align="center">
    <Spinner label="Primary" />
    <Spinner label="Secondary" style={{ "--k-spinner-color": "var(--k-color-theme-secondary)" } as CSSProperties} />
    <Spinner label="Decorative" style={{ "--k-spinner-color": "var(--k-color-theme-decorative)" } as CSSProperties} />
  </Stack>
);
import type { CSSProperties } from "react";
import { Spinner } from "@kesko/components";

export default () => <Spinner style={{ "--k-spinner-size": "2rem" } as CSSProperties} />;
import { Spinner } from "@kesko/components";

export default () => <Spinner label="Loading order history" />;
import type { CSSProperties } from "react";
import { Spinner, Stack } from "@kesko/components";

export default () => (
  <Stack align="center" justify="center" className="k-bg-panel k-rounded-md k-p-xl" style={{ minBlockSize: "12rem" }}>
    <Spinner size="lg" style={{ "--k-spinner-color": "var(--k-color-border-divider)" } as CSSProperties} label="Loading order history" />
  </Stack>
);
import { Spinner, Stack } from "@kesko/components";

export default () => (
  <Stack direction="row" gap="lg" align="center">
    <Spinner size="sm" />
    <Spinner />
    <Spinner size="lg" />
    <Spinner size="xl" />
    <Spinner size="2xl" />
  </Stack>
);

Properties

NameDescriptionTypeDefault
size

The size of the spinner.

"sm" | "md" | "lg" | "xl" | "2xl""md"
label

Accessible label for the spinner.

string—
aria-hidden

Hides the spinner from assistive technology and drops its role and label. Use it when the wait is announced elsewhere, as Button does with loadingLabel.

boolean | "true" | "false"—

Styles

CSS custom properties provide finer-grained control than props. Prefer the props API when it suits your need.

NameDescriptionDefault
--k-spinner-color

Overrides the spinner color.

var(--k-color-theme-primary)
--k-spinner-size

Overrides the spinner size.

var(--k-size-spinner-md)

Accessibility #

The spinner is a named role="status" region. Screen readers announce its label when the user moves to it, but not reliably when it first appears.

  • Say what is loading. The default label is “Loading”. When the page has more than one thing that can load, pass a label that names it, for example “Ladataan tilaushistoriaa”, so the announcement makes sense out of context.
  • Show one spinner per wait. Every spinner announces itself. A list of placeholder rows that each carry a spinner reads as a wall of “Loading” to a screen reader. Put one spinner on the container instead.
  • Use the button’s own loading state. For a wait triggered by a button, pass loading to the Button rather than placing a spinner next to it. The button keeps its size, blocks repeat clicks and renders the spinner for you; set its loadingLabel the same way you would set label here.
  • Keep it for short waits. A spinner tells people something is happening, not how long it takes. For anything longer than a few seconds, show progress or a message that explains the wait.
  • Remove it when the wait ends. Leaving a spinner in the DOM after content has arrived leaves a stale status region. Render the content in its place, or move focus to the result when the user triggered the load.
  • Check contrast when you override the color. The spinner uses the primary theme color, which passes 3:1 on the page and panel backgrounds of every brand. If you set --k-spinner-color yourself, the dots need 3:1 against the background they sit on.

Reduced motion and forced colors are handled for you: the bounce becomes a gentle pulse under prefers-reduced-motion, and the dots stay visible in Windows high-contrast mode. See the accessibility guidelines and the A11Y checklist for more details.


Usage #

There are two necessary parts to using the Spinner component. The @kesko/components package and the CSS Framework are required. Everything else is optional:

npm install @kesko/components @kesko/css

Once installed, load the CSS Framework in your app’s entry point or root layout:

import "@kesko/css";

Then, you can import the Spinner:

import { Spinner } from "@kesko/components";

Projects without React can get the same styles from @kesko/css by importing the components stylesheet as well:

@import "@kesko/css";
@import "@kesko/css/components";

Resources #