OTTODesign System

Components

Spinner

The spinner provides users with a visual indicator for a loading state.

Configurator

LiveSpinner: size and variant. Switch the ground to Frame, or use Inverted on a dark area.
HTML
<oc-spinner-v1 variant="default" size="100"></oc-spinner-v1>

Usage

Anatomy

1 2
  1. Indicator (rotates)
  2. Track
LiveAnatomy
HTML
<div class="anatomy" style="margin:32px 48px">
<oc-spinner-v1 variant="default" size="200"></oc-spinner-v1>
<span class="anatomy-pin" style="left:-8%;top:10%">1</span>
<span class="anatomy-pin" style="left:108%;top:90%">2</span>
<ol class="anatomy-key"><li data-n="1">Indicator (rotates)</li><li data-n="2">Track</li></ol>

Variants

The spinner is available in sizes 50, 100 and 200. The spinner has following variants:

Size 50, 100, 200; default on light, inverted on dark

Livesizes 50, 100 and 200 in default and inverted
HTML
<div class="on-frame" style="margin:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px">
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="default" size="50"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="default" size="100"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="default" size="200"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-inverted, #212121);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="inverted" size="50"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-inverted, #212121);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="inverted" size="100"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-inverted, #212121);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="inverted" size="200"></oc-spinner-v1></div>
<p class="demo-label" style="margin-top:12px">Size 50, 100, 200; default on light, inverted on dark</p>

Behavior

Interaction

The spinner is not interactive.

Animation

The track of the spinner turns clockwise in a loop. One turn takes 800ms with a continuous ease.

One full rotation takes 800 ms and loops until loading is done

Liveloop animation
HTML
<div class="on-frame" style="margin:0;display:grid;grid-template-columns:repeat(1,minmax(0,1fr));gap:8px">
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-spinner-v1 variant="default" size="200"></oc-spinner-v1></div>
<p class="demo-label" style="margin-top:12px">One full rotation takes 800 ms and loops until loading is done</p>

Placement

Place the spinner standalone or inside of other components. It is also used within button, icon button or switch. Use the default variant on light backgrounds. Use the inverted variant of the spinner on dark backgrounds. Ensure there is always enough color contrast according to the accessibility guidelines.

On the frame

On the canvas

On dark: inverted

Livestandalone placement
HTML
<div class="on-frame" style="margin:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px">
<div style="padding:40px 16px;display:grid;place-items:center;gap:12px"><p class="demo-label">On the frame</p><oc-spinner-v1 variant="default" size="200"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center;gap:12px"><p class="demo-label">On the canvas</p><oc-spinner-v1 variant="default" size="200"></oc-spinner-v1></div>
<div style="background:var(--oc-semantic-color-background-inverted, #212121);padding:40px 16px;display:grid;place-items:center;gap:12px"><p class="demo-label" style="color:#fff">On dark: inverted</p><oc-spinner-v1 variant="inverted" size="200"></oc-spinner-v1></div>
In den Warenkorb
Liveinside component placement
HTML
<div class="on-frame" style="margin:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px">
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-button-v1 variant="primary" loading fit-content>In den Warenkorb</oc-button-v1></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-icon-button-v3 variant="primary" size="100" icon="wishlist" loading oc-aria-label="Merken"></oc-icon-button-v3></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center"><oc-switch-v3 loading><input type="checkbox" aria-label="oc-auto"><label slot="label">Newsletter</label></oc-switch-v3></div>

Spinner vs. skeleton

Use the spinner if a process is happening asynchronously and no preview is possible, such as submitting a form. In contrast to this, use the skeleton if you want to give a preview of loading content and to avoid unexpected changes to the layout (CLS).

Daten werden übermittelt
Livespinner and skeleton
HTML
<div class="on-frame" style="margin:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px">
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center;justify-items:stretch;gap:24px;padding:24px"><oc-auth-field-v1><input type="password" id="spinner-vs-skeleton-pw" value="geheim"><label for="spinner-vs-skeleton-pw">Passwort</label></oc-auth-field-v1><oc-button-v1 variant="secondary" loading>Daten werden übermittelt</oc-button-v1></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);padding:40px 16px;display:grid;place-items:center;justify-items:stretch;padding:24px"><oc-skeleton-v1 width="100%" height="128px" border-radius="0px"></oc-skeleton-v1></div>

Best practices

DoUse only one standalone spinner at a time.
Don'tUse multiple standalone spinners at the same time.

Accessibility

For information on accessibility, refer to the technical documentation.

Status

Implementation

Live demo

Zusammenfassung

Over-Ear-Kopfhörer

Over-Ear-Kopfhörer mit Noise Cancelling

Menge: 1

Zwischensumme59,99 €
Versand2,95 €
Gesamtsumme62,94 €
Zahlungspflichtig bestellen

Deine Bestellung wird übermittelt …

Suche nach „Sessel“

Wir suchen passende Artikel für dich.

LiveReal OTTO components, rendered by the OTTO component runtime
HTML
<div class="on-frame" style="margin:0;padding:24px;display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:16px;align-items:start">
<div style="background:var(--oc-semantic-color-background-canvas, #fff);border-radius:16px;padding:24px;display:flex;flex-direction:column;gap:16px;box-shadow:0 0 0 1px rgba(0,0,0,.06)"><p class="demo-title" style="font-size:1.125rem">Zusammenfassung</p><div style="display:flex;gap:12px;align-items:center"><img src="/previews/imagery/samples/otto-product-still/product-headphones.webp" alt="Over-Ear-Kopfhörer" width="64" height="64" style="margin:0;border-radius:12px;background:#f3f3f3"><div><p class="demo-copy">Over-Ear-Kopfhörer mit Noise Cancelling</p><p class="demo-copy" style="color:var(--oc-semantic-color-text-secondary, #6d6d6d)">Menge: 1</p></div></div><div style="display:flex;justify-content:space-between;gap:16px"><span class="demo-copy">Zwischensumme</span><span class="demo-copy">59,99 €</span></div><div style="display:flex;justify-content:space-between;gap:16px"><span class="demo-copy">Versand</span><span class="demo-copy">2,95 €</span></div><div style="display:flex;justify-content:space-between;border-top:1px solid rgba(0,0,0,.1);padding-top:12px"><strong>Gesamtsumme</strong><strong>62,94 €</strong></div><oc-button-v1 variant="primary" loading>Zahlungspflichtig bestellen</oc-button-v1><p class="demo-copy" style="color:var(--oc-semantic-color-text-secondary, #6d6d6d);text-align:center">Deine Bestellung wird übermittelt …</p></div>
<div style="background:var(--oc-semantic-color-background-canvas, #fff);border-radius:16px;padding:24px;display:flex;flex-direction:column;gap:16px;box-shadow:0 0 0 1px rgba(0,0,0,.06)"><p class="demo-title" style="font-size:1.125rem">Suche nach „Sessel“</p><div style="display:grid;place-items:center;gap:12px;padding:32px 0"><oc-spinner-v1 variant="default" size="200"></oc-spinner-v1><p class="demo-copy" style="color:var(--oc-semantic-color-text-secondary, #6d6d6d)">Wir suchen passende Artikel für dich.</p></div></div>

Code

Version Tag Status API
v1 <oc-spinner-v1> Stable, allowed for generation SpinnerV1

Overview (v1)

Spinner

The spinner component provides a visual indicator for the loading state. It has attributes for setting the size and styling variants.

Default variation
HTML
<oc-spinner-v1 size="100" variant="default"></oc-spinner-v1>
Configuration

The spinner component offers the styling variants default and inverted. This component is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the spinner component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Accessibility

The spinner component comes with a set of built-in accessibility features to ensure a seamless experience for all users.

The SVG element is set to aria-hidden="true" to prevent screen readers from reading the spinner image element.

When using the spinner consider using an ARIA live region for screen reader support or using our global srSpeak utility.```

Further reading

Configuration (v1)

Spinner configuration

Configure the spinner component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

HTML
<oc-spinner-v1 size="100" variant="default"></oc-spinner-v1>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

API v1

Spinner v1 API

API: <oc-spinner-v1> (SpinnerV1)

The spinner component provides a visual indicator for the loading state. It has attributes for setting the size and styling variants.

Attributes / properties
Attribute Type Default Required Description
variant "default" | "inverted" "default" no Sets the main styling of the spinner.
size "50" | "100" | "200" "100" no Sets the size of the spinner.
Events
Event Detail type Description
oc-property-change OcSpinnerV1Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.

Variations (v1)

Variations

Listed below are the most common variations of the spinner component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-spinner-variations--default · tags: components

The default configuration uses the default variant.

HTML
<oc-spinner-v1 size="100" variant="default"></oc-spinner-v1>
Inverted

Story: components-spinner-variations--inverted · tags: components

The inverted variant renders the spinner with an inverted color scheme.

Args: variant=inverted

HTML
<oc-spinner-v1 size="100" variant="inverted"></oc-spinner-v1>
Demo: Accessibility

Story: components-spinner-variations--demo-accessibility · tags: components

<button id="spinner-button">Press To Load</button>

<script>
  (() => {
    const button = document.getElementById("spinner-button");
    const spinner = document.createElement("oc-spinner-v1");

    button.addEventListener("click", () => {
      button.ariaBusy = "true";
      button.after(spinner);
      window.otto.ally.srSpeak("Opening Document");

      setTimeout(() => {
        button.ariaBusy = "false";
        spinner.remove();
      }, 1000);
    });
  })();
</script>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Accessibility",
  parameters: {
    chromatic: {
      disableSnapshot: true,
      hideInChromatic: true
    }
  },
  render() {
    return html`
      <button id="spinner-button">Press To Load</button>

      <script>
        (() => {
          const button = document.getElementById("spinner-button");
          const spinner = document.createElement("oc-spinner-v1");

          button.addEventListener("click", () => {
            button.ariaBusy = "true";
            button.after(spinner);
            window.otto.ally.srSpeak("Opening Document");

            setTimeout(() => {
              button.ariaBusy = "false";
              spinner.remove();
            }, 1000);
          });
        })();
      </script>
    `;
  }
}