Spinner component is an animated icon that lets users know content or result of an action is being loaded.
import { Spinner } from "@kesko/components";
export default () => <Spinner />;<k-spinner role="status" aria-label="Loading"></k-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>
);<k-stack direction="row" gap="lg" align="center">
<k-spinner role="status" aria-label="Primary"></k-spinner>
<k-spinner role="status" aria-label="Secondary" style="--k-spinner-color: var(--k-color-theme-secondary)"></k-spinner>
<k-spinner role="status" aria-label="Decorative" style="--k-spinner-color: var(--k-color-theme-decorative)"></k-spinner>
</k-stack>import type { CSSProperties } from "react";
import { Spinner } from "@kesko/components";
export default () => <Spinner style={{ "--k-spinner-size": "2rem" } as CSSProperties} />;<k-spinner role="status" aria-label="Loading" style="--k-spinner-size: 2rem"></k-spinner>import { Spinner } from "@kesko/components";
export default () => <Spinner label="Loading order history" />;<k-spinner role="status" aria-label="Loading order history"></k-spinner>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>
);<k-stack align="center" justify="center" class="k-bg-panel k-rounded-md k-p-xl" style="min-block-size: 12rem">
<k-spinner role="status" aria-label="Loading order history" size="lg" style="--k-spinner-color: var(--k-color-border-divider)"></k-spinner>
</k-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>
);<k-stack direction="row" gap="lg" align="center">
<k-spinner role="status" aria-label="Loading" size="sm"></k-spinner>
<k-spinner role="status" aria-label="Loading"></k-spinner>
<k-spinner role="status" aria-label="Loading" size="lg"></k-spinner>
<k-spinner role="status" aria-label="Loading" size="xl"></k-spinner>
<k-spinner role="status" aria-label="Loading" size="2xl"></k-spinner>
</k-stack>Properties
| Name | Description | Type | Default |
|---|---|---|---|
size | The size of the spinner. | "sm" | "md" | "lg" | "xl" | "2xl" | "md" |
label | Accessible label for the spinner. | string | — |
Styles
CSS custom properties provide finer-grained control than props. Prefer the props API when it suits your need.
| Name | Description | Default |
|---|---|---|
--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
labelthat 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
loadingto 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 itsloadingLabelthe same way you would setlabelhere. - 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-coloryourself, 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/csspnpm add @kesko/components @kesko/cssyarn add @kesko/components @kesko/cssbun add @kesko/components @kesko/cssOnce 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 #
Usage guidelines
Learn how to use the component library with React, Next.js, or basic HTML.
Localization
How to translate the components for multiple languages.
CSS Framework
Utilities and tokens for everything the components don’t cover.
Themes
How to customize the component library theme.
Accessibility checklist
Interactive, browser-based Kesko accessibility checklist.