跳到主要内容

Loader

Spinner in one of four animations, for work whose duration is unknown. Pick the animation explicitly — the component has no default worth having.

LoaderLoader

Use this when / not when​

  • Use while waiting for something whose progress cannot be measured: a request, a save, a panel that has not loaded yet.
  • Not when the shape of what is coming is known — a skeleton reads better and does not move the layout when the content arrives. That is RectangleSkeleton.
  • Not when progress can be measured: ProgressBar.
  • Not inside a button that is saving — Button has isLoading, which places and sizes its own loader.

Import​

import { Loader, LoaderTypes } from "@onlyoffice/apps-ui-kit/components/loader";

Also exported from the root barrel @onlyoffice/apps-ui-kit.

Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme above it in the tree for the track colours; without it the animation falls back to the pale default stroke.

Stories​

Default​

A line of plain text instead of an animation, for a place where a moving spinner would distract: this is what you get with type set to base or left out, so pick an animation explicitly when you want one. Change any other prop live in the Controls panel below.

DefaultDefault

Oval​

Oval spinner animation, commonly used for inline loading states.

OvalOval

Dual Ring​

Dual ring animation with two concentric spinning rings.

Dual RingDual Ring

Rombs​

Rombs (diamond) animation, used as the main application loader.

RombsRombs

Track​

Track animation for compact loading indicators.

TrackTrack

All Types​

Side-by-side comparison of the text fallback (Base) and the four animations (Oval, DualRing, Rombs and Track), to choose the one that fits the space it waits in.

All TypesAll Types

Custom Colors​

DualRing loaders with different custom colors applied via the color prop.

Custom ColorsCustom Colors

Different Sizes​

Oval loaders at three different sizes to demonstrate scalability.

Different SizesDifferent Sizes

On Primary Button​

A white track on the accent background of a primary button, where the default accent-coloured track would disappear (primary).

On Primary ButtonOn Primary Button

Disabled State​

The track dimmed beside a normal one, for a loader inside a control that is currently unavailable (isDisabled, read by the track only).

Disabled StateDisabled State

Css Customization​

Every overridable variable set on one wrapper -- the variables are listed under CSS variables on this page.

The example shows, from left to right: an oval for --loader-stroke and --loader-size, which every instance picks up; a track for --loader-track-base; a track with primary for --loader-track-primary; and a track with isDisabled for --loader-opacity-disabled.

Css CustomizationCss Customization

Minimal example​

type is what makes it spin. Without it you get a line of text.

import { Loader, LoaderTypes } from "@onlyoffice/apps-ui-kit/components/loader";

export function PanelLoader() {
return (
<div style={{ display: "flex", justifyContent: "center", padding: 24 }}>
<Loader type={LoaderTypes.oval} size="32px" label="Loading rooms" />
</div>
);
}

Props​

PropertyTypeDescription
className?stringApplied to the wrapper around the animation, not to the animation.
color?stringAny CSS colour, applied as the stroke of the animation and the colour of the base type's text.
id?stringApplied to the wrapper.
isDisabled?booleanDims the animation to the disabled opacity. Read by the track type only.
label?stringAccessible name of the animation, set as its aria-label. For the base type it is not a label at all but the entire rendered content.
primary?booleanUses the primary button's track colour, for a loader drawn on top of a primary button. Read by the track type only.
ref?RefObject<SVGSVGElement>Reaches the <svg> of the track type; the other types ignore it.
size?stringSize of the animation as a CSS length, applied to both axes. The stylesheet falls back to 40px for most types and 20px for track. For the base type this is the font size of the text instead.
style?CSSPropertiesApplied to the wrapper, and again to the inner span of the base type.
type?LoaderTypesWhich animation to render. There is no default, and base is not an animation: both it and an absent type fall through to a branch that renders label as plain text and nothing else. Pass oval, dualRing, rombs or track for something that spins.

Enums​

EnumMembers
LoaderTypesbase, oval, dualRing, rombs, track

Recipes​

Disabled​

isDisabled dims the animation. Only the track type reads it, and it is meant for a loader drawn on a control that is itself disabled.

import { Loader, LoaderTypes } from "@onlyoffice/apps-ui-kit/components/loader";

export function DisabledTrack() {
return <Loader type={LoaderTypes.track} size="20px" isDisabled />;
}

Centred in a panel that has not loaded​

import type { ReactNode } from "react";
import { Loader, LoaderTypes } from "@onlyoffice/apps-ui-kit/components/loader";

export function PanelBody({
isLoading,
children,
}: {
isLoading: boolean;
children: ReactNode;
}) {
if (!isLoading) return <>{children}</>;

return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
minHeight: 160,
}}
>
<Loader type={LoaderTypes.dualRing} size="40px" label="Loading" />
</div>
);
}

Behaviour the types don't state​

  • LoaderTypes.base is not a spinner. It is the branch the switch falls through to, and it renders label as plain text with no animation at all. An absent type does the same thing, so a <Loader /> on its own renders nothing visible. Always pass oval, dualRing, rombs or track.
  • Loader.default is decoration. The component carries a static object naming a type, a size and a label, and nothing reads it — the props have no defaults. The sizes quoted in the table come from the stylesheet's own fallbacks.
  • The wrapper is a plain <div> with no width, height or centring of its own. Place it yourself; the examples above do.
  • The four animations differ in shape: oval is a ring with one spinning arc, dualRing two concentric rings turning in opposite directions, rombs three diamonds that bounce in turn, and track a ring of six segments spinning together.
  • color reaches the oval and dualRing strokes and the base text only. The track takes its colour from the theme (or primary), and the rombs diamonds keep their own blue, green and red.
  • rombs needs a positioned container. The diamonds are absolutely positioned <div>s that move between top: 0 and top: 120px, so they sit against the nearest positioned ancestor and need about size plus 120px of height below it.
  • Give every track its own id. The track builds its gradient ids from id (spinner-color-<id>-1 and on); two tracks with the same or no id share one set of gradients, and the second draws in the first one's colour.
  • ref reaches the track type's <svg> alone; the other types ignore it.
  • primary and isDisabled are read by the track type alone; the other three ignore them.

CSS variables​

VariableDefaultEffect
--loader-strokethe color propStroke of the oval and dualRing animations; a color passed to the dual ring still wins, being set on its rings
--loader-size40px (20px for track)Width and height of the oval, dualRing and track animations when size is not set; rombs ignores it
--loader-track-basetheme (main button colour; white in dark)Colour of the track
--loader-track-primary#ffffffColour of the track with primary set
--loader-opacity-disabled0.6Opacity of the track under isDisabled

A size prop sets --loader-size on the animation itself and so beats a value set on a wrapper. --loader-color cannot be set from outside at all: the stylesheet defines it on the animation, so pass color instead.

Accessibility​

  • The wrapper carries aria-busy="true", which tells assistive technology that the region is updating. It sets no role="status", so the change is not announced on its own.
  • label becomes the aria-label of the oval, dualRing and track animations. Without it the dual ring falls back to its built-in title, "dual ring"; the oval's and the track's titles are not direct children of the <svg>, so those two are unnamed graphics.
  • rombs ignores label entirely: give its container an accessible name yourself.
  • The base type is read as its plain text.
  • Nothing here manages focus. A loader that replaces a focused control leaves focus on the document.

Test ids​

Elementdata-testid
The wrapperloader
oval animationoval-loader
dualRing animationdual-ring-loader
rombs animationrombs-loader
track animationtrack-loader

None of these can be overridden by a prop.