Spinner

ui-spinner is a small rotating arc that shows work in progress. It has the role status and an accessible name taken from label, which defaults to "Loading". By default it inherits the current text colour. variant picks a theme colour instead.

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <ui-spinner></ui-spinner>
</body>
</html>

Examples

Sizes

size is the width and height in pixels, at least 8.

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <ui-spinner size="12"></ui-spinner>
  <ui-spinner size="16"></ui-spinner>
  <ui-spinner size="24"></ui-spinner>
  <ui-spinner size="32"></ui-spinner>
</body>
</html>

Colour

variant sets the colour of the arc. The default variant uses currentColor, so it matches the surrounding text.

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <ui-spinner size="24"></ui-spinner>
  <ui-spinner size="24" variant="primary"></ui-spinner>
  <ui-spinner size="24" variant="muted"></ui-spinner>
  <ui-spinner size="24" variant="destructive"></ui-spinner>
</body>
</html>

In a button

Show a spinner inside a disabled button while a request runs.

Previewindex.htmlspinner-button-demo.html
Save changes
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <import-element from="./spinner-button-demo.html"></import-element>
  <spinner-button-demo></spinner-button-demo>
</body>
</html>
<custom-element name="spinner-button-demo">
  <script>
    const request = useState({ busy: false });

    function save() {
      request.busy = true;
      const timer = setTimeout(() => {
        request.busy = false;
      }, 1500);
      signal.addEventListener("abort", () => clearTimeout(timer), { once: true });
    }
  </script>
  <ui-button _disabled="#request.busy" onclick="save()">
    <is-visible when="#request.busy"><ui-spinner size="14" label="Saving"></ui-spinner></is-visible>
    Save changes
  </ui-button>
</custom-element>

With a badge

Previewindex.html
Syncing Processing
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/badge.html"></import-element>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <ui-badge variant="secondary"><ui-spinner size="12" label="Syncing"></ui-spinner> Syncing</ui-badge>
  <ui-badge variant="outline"><ui-spinner size="12" label="Processing"></ui-spinner> Processing</ui-badge>
</body>
</html>

Custom label

Change label to describe the work. It becomes the spinner's accessible name.

Previewindex.html
Loading messages…
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spinner demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
  <style>
    .demo-row-tight {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: calc(var(--spacing) * 2);
    }
    .demo-muted {
      margin: 0;
      font-size: var(--text-sm);
      color: var(--muted-foreground);
    }
  </style>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/spinner.html"></import-element>

  <div class="demo-row-tight demo-muted">
    <ui-spinner label="Loading messages"></ui-spinner>
    Loading messages…
  </div>
</body>
</html>

API

Parts

Part Slot Renders
ui-spinner (default) A rotating arc drawn with an inline <svg>. It has no slot and takes no content.

Attributes

Attribute Type Default Description
size number 16 Width and height in pixels. Minimum 8.
label string "Loading" Accessible name of the spinner.
variant "default" | "primary" | "muted" | "destructive" "default" Colour of the arc. default uses currentColor.

CSS parts

None. Set color on the element to use a colour outside the variants.

Accessibility

The element has the role status and its aria-label comes from label, both through ElementInternals. The SVG is hidden from assistive technology. With reduced motion preferred, the rotation slows to a third of its normal speed instead of stopping, so the indicator still shows that something is happening.

Edit this page on GitHub · View as Markdown