# Progress bar

Progress bars communicate system information, like how much cloud storage someone is using in OneDrive, or task information, like how long until a download is complete.

## Best practices

### Do

- Use determinate progress bars whenever progress can be measured.
- Combine related steps into one continuously advancing progress bar.
- Use brief, descriptive -ing verbs followed by an ellipsis in status text.

### Don't

- Interrupt an indeterminate progress bar in the middle of an animation.
- Include time estimates unless they are reliable.
- Add a period to the progress label.

## Behavior and states

- Progress bars can be either determinate or indeterminate, depending on the needs of your app and the capabilities of the technology you’re building on.
- Use determinate progress bars whenever possible. They communicate status and assure people things are still working.
- Only use indeterminate progress bars for short tasks.
- If enough data is gathered after a task starts and it becomes possible to communicate how much time is left, switch to a determinate progress bar.
- Progress bars should only be used for tasks that take longer than a second.
- If you’re loading new content with a known structure that doesn’t block the UI, try a skeleton.

## Default

Source: CoreAI.

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

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

import type { ProgressBarProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import * as React from 'react';

export const Default = (props: Partial<ProgressBarProps>): JSXElement => {
    return (<Field validationMessage="Default ProgressBar" validationState="none">
      <ProgressBar {...props} value={0.5}/>
    </Field>);
};

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.

### ProgressBar API

A ProgressBar bar shows the progression of a task.

```ts
interface ProgressBarProps {
  as?: "div";

  /**
   * The filled portion of the ProgressBar bar. Animated in the indeterminate state, when no value is provided.
   */
  bar?: NonNullable<WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  children?: any;

  className?: string;

  /**
   * The status of the ProgressBar bar. Changes the color of the bar.
   * @default brand
   */
  color?: string;

  /**
   * Motion slot for the indeterminate animation. Pass `null` to disable the animation.
   */
  indeterminateMotion?: MotionSlotProps | null;

  /**
   * The maximum value, which indicates the task is complete.
   * The ProgressBar bar will be full when `value` equals `max`.
   * @default 1
   */
  max?: number;

  ref?: Ref<HTMLDivElement>;

  /**
   * The shape of the bar and track.
   * @default rounded
   */
  shape?: "rounded" | "square";

  style?: CSSProperties;

  /**
   * The thickness of the ProgressBar bar
   * @default medium
   */
  thickness?: "medium" | "large";

  /**
   * A decimal number between `0` and `1` (or between `0` and `max` if given),
   * which specifies how much of the task has been completed.
   *
   * If `undefined` (default), the ProgressBar will display an **indeterminate** state.
   */
  value?: number;
}
```

## 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.

## Color

Source: Fluent, adapted for CoreAI.

The `color` prop can be used to indicate a `"brand"` state (default), `"error"` state (red), `"warning"` state (orange), or `"success"` state (green).

[Download source](/coreai-design-system/source/examples/components-progressbar--color.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 { Field } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: '20px',
    },
});

export const Color = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.container}>
      <Field validationMessage="Error ProgressBar">
        <ProgressBar value={0.75} color="error"/>
      </Field>

      <Field validationMessage="Warning ProgressBar" validationState="warning">
        <ProgressBar value={0.95} color="warning"/>
      </Field>

      <Field validationMessage="Success ProgressBar" validationState="success">
        <ProgressBar value={1} color="success"/>
      </Field>
    </div>);
};

export default Color;
```

## Indeterminate

Source: Fluent, adapted for CoreAI.

ProgressBar is indeterminate when 'value' is undefined.
      Indeterminate ProgressBar is best used to show that an operation is being executed.

[Download source](/coreai-design-system/source/examples/components-progressbar--indeterminate.tsx)

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

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

export const Indeterminate = (): JSXElement => {
    return (<Field validationMessage="Indeterminate ProgressBar" validationState="none">
      <ProgressBar />
    </Field>);
};

export default Indeterminate;
```

## Max

Source: Fluent, adapted for CoreAI.

You can specify the maximum value of the determinate ProgressBar.
      This is useful for instances where you want to show capacity, or how much of a total has been
      uploaded/downloaded.

[Download source](/coreai-design-system/source/examples/components-progressbar--max.tsx)

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

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

const intervalIncrement = 1;

const intervalDelay = 100;

export const Max = (): JSXElement => {
    const [value, setValue] = React.useState(0);
    React.useEffect(() => {
        const id = setInterval(() => {
            setValue(value < 42 ? intervalIncrement + value : 0);
        }, intervalDelay);
        return () => {
            clearInterval(id);
        };
    });
    return (<Field validationMessage={`There have been ${value} files downloaded`} validationState="none">
      <ProgressBar max={42} value={value}/>
    </Field>);
};

export default Max;
```

## Motion Custom

Source: Fluent, adapted for CoreAI.

The indeterminate animation can be customized using the [Motion APIs](https://react.fluentui.dev/?path=/docs/motion-apis-createmotioncomponent--docs), together with the `indeterminateMotion` slot.

[Download source](/coreai-design-system/source/examples/components-progressbar--motion-custom.tsx)

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

import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import { createMotionComponent } from "@coreai-ds/react-components";
import * as React from 'react';

// A custom motion component that swings between left and right, instead of always moving to the right.
// The reduced motion version of the animation moves more slowly, with no acceleration, using a gentler gradient.
const SwingMotion = createMotionComponent({
    // translate percentages are relative to the element's own width, not the container's.
    // The indeterminate bar is ~33% the width of its container, so:
    //   translate: '-100%' === left: '-33%' (one bar-width off-screen to the left)
    //   translate: '300%'  === left: '100%' (3 × bar-width ≈ full container width, off-screen to the right)
    keyframes: [{ translate: '-100%' }, { translate: '300%' }],
    duration: 2000,
    easing: 'ease-in-out',
    direction: 'alternate', // loop by reversing direction
    iterations: Infinity,
    reducedMotion: {
        // The gradient bar is 100% of the container for reduced motion, which is 3x wider
        keyframes: [{ translate: '-100%' }, { translate: '100%' }],
        duration: 6000, // slower speed
        easing: 'linear', // no acceleration
    },
});

export const MotionCustom = (): JSXElement => (<Field validationMessage="Custom indeterminate animation" validationState="none">
    <ProgressBar indeterminateMotion={{
        children: (_, motionProps) => <SwingMotion {...motionProps}/>,
    }}/>
  </Field>);

export default MotionCustom;
```

## Shape

Source: Fluent, adapted for CoreAI.

The `shape` prop affects the corners of the bar. It can be `rounded` (default) or `square`.

[Download source](/coreai-design-system/source/examples/components-progressbar--shape.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 { Field } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        margin: '20px 0px',
    },
});

export const Shape = (): JSXElement => {
    const styles = useStyles();
    return (<div>
      <Field validationMessage="Rounded ProgressBar" validationState="none">
        <ProgressBar className={styles.container} shape="rounded" thickness="large" value={0.5}/>
      </Field>
      <Field validationMessage="Square ProgressBar" validationState="none">
        <ProgressBar className={styles.container} shape="square" thickness="large" value={0.5}/>
      </Field>
    </div>);
};

export default Shape;
```

## Thickness

Source: Fluent, adapted for CoreAI.

The `thickness` prop affects the size of the bar. It can be `medium` (default) or `large`.

[Download source](/coreai-design-system/source/examples/components-progressbar--thickness.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 { Field } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        margin: '20px 0px',
    },
});

export const Thickness = (): JSXElement => {
    const styles = useStyles();
    return (<div>
      <Field validationMessage="Medium ProgressBar" validationState="none">
        <ProgressBar className={styles.container} thickness="medium" value={0.7}/>
      </Field>

      <Field validationMessage="Large ProgressBar" validationState="none">
        <ProgressBar className={styles.container} thickness="large" value={0.7}/>
      </Field>
    </div>);
};

export default Thickness;
```

## Resources

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