# Spinner

Spinners visually communicate that something is processing. They’re used for loading states that take more than a second.

## Best practices

### Do

- Use a spinner for processing or loading states lasting more than one second.
- Center it over the section that is loading.
- Add a label when the process is expected to exceed three seconds.

### Don't

- Let one loading section block interaction with unrelated sections.
- Use a spinner to communicate measurable progress; use a determinate progress bar.
- Use vague status labels.

## Behavior and states

- Center the spinner over the section of the page that’s loading.
- A spinner for one loading section shouldn’t block interaction with other sections.
- Use a label when a process will take longer than three seconds.
- Keep spinner labels brief, specific, and three words or less.
- Spinners don’t show how much time is left before the process is done.
- To communicate a more specific status, try a determinate progress bar instead.

## Default

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-spinner--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { SpinnerProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { Spinner } from "@coreai-ds/react-components";
import * as React from 'react';

export const Default = (props: Partial<SpinnerProps>): JSXElement => <Spinner {...props}/>;

export default Default;
```

## API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. `?` means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

### Spinner API

Converged Spinner component for the fluentui repo

```ts
interface SpinnerProps {
  /**
   * The appearance of the Spinner.
   * @default 'primary'
   */
  appearance?: "inverted" | "primary";

  as?: "div" | "span";

  children?: any;

  className?: string;

  /**
   * Time in milliseconds after component mount before spinner is visible.
   * @default 0
   */
  delay?: number;

  /**
   * An optional label for the Spinner.
   */
  label?: WithSlotShorthandValue<Omit<ComponentProps<LabelSlots>, "required"> & { disabled?: boolean; required?: boolean | WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null | undefined; }, "children"> & { children?: any; }> | null | undefined; size?: "small" | "medium" | "large" | undefined; weight?: "regular" | "semibold" | undefined; } & RefAttributes<HTMLLabelElement>> | null | undefined;

  /**
   * Where the label is positioned relative to the Spinner
   * @default 'after'
   */
  labelPosition?: "above" | "below" | "before" | "after";

  ref?: Ref<HTMLSpanElement>;

  /**
   * The size of the spinner.
   * @default 'medium'
   */
  size?: "small" | "medium" | "large" | "extra-large" | "tiny" | "extra-small" | "huge" | "extra-tiny";

  /**
   * The animated spinning ring.
   */
  spinner?: WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * The part of the spinner that rotates.
   */
  spinnerTail?: NonNullable<WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  style?: CSSProperties;
}
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Import components from `@coreai-ds/react-components`. CoreAI guidance above takes precedence over API demonstration examples.

## Appearance

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-spinner--appearance.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Spinner } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        '> div': { padding: '20px' },
    },
    // Inverted Spinners are meant as overlays (e.g., over an image or similar)
    // so give it a solid, dark background so it is visible in all themes.
    invertedWrapper: {
        backgroundColor: tokens.colorBrandBackgroundStatic,
    },
});

export const Appearance = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.container}>
      <Spinner appearance="primary" label="Primary Spinner"/>

      <div className={styles.invertedWrapper}>
        <Spinner appearance="inverted" label="Inverted Spinner"/>
      </div>
    </div>);
};

export default Appearance;
```

## Labels

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-spinner--labels.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Spinner } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        '> div': { padding: '20px' },
    },
});

export const Labels = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.container}>
      <Spinner labelPosition="before" label="Label Position Before..."/>

      <Spinner labelPosition="after" label="Label Position After..."/>

      <Spinner labelPosition="above" label="Label Position Above..."/>

      <Spinner labelPosition="below" label="Label Position Below..."/>
    </div>);
};

export default Labels;
```

## Size

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-spinner--size.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Spinner } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        '> div': { padding: '20px' },
    },
});

export const Size = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.container}>
      <Spinner size="extra-tiny" label="Extra Tiny Spinner"/>

      <Spinner size="tiny" label="Tiny Spinner"/>

      <Spinner size="extra-small" label="Extra Small Spinner"/>

      <Spinner size="small" label="Small Spinner"/>

      <Spinner size="medium" label="Medium Spinner"/>

      <Spinner size="large" label="Large Spinner"/>

      <Spinner size="extra-large" label="Extra Large Spinner"/>

      <Spinner size="huge" label="Huge Spinner"/>
    </div>);
};

export default Size;
```

## Resources

- [Figma component](https://www.figma.com/design/eXfSQrRg3poHRgmr0ivN5V/CoreAI-Figma-Library?node-id=7234-133747)
- [Fluent guidance](https://fluent2.microsoft.design/components/web/react/core/spinner/usage)