> ## Documentation Index
> Fetch the complete documentation index at: https://www.beeq.design/llms.txt
> Use this file to discover all available pages before exploring further.

# Progress

> Progress bars visually represent the completion status of a task or process, giving users real-time feedback on how much has been done and what remains.

export const CodeLivePreview = ({code, children, height, removePadding = false, mode = 'shadow'}) => {
  const previewRef = useRef(null);
  const BEEQ_ESM_URL = 'https://esm.sh/@beeq/core/dist/beeq/beeq.esm.js';
  const BEEQ_CSS_URL = 'https://esm.sh/@beeq/core/dist/beeq/beeq.css';
  const BEEQ_ICONS_URL = 'https://esm.sh/@beeq/core/dist/beeq/svg';
  const ensureParentBeeqRuntime = () => {
    if (document.querySelector('script[data-beeq-parent-runtime]')) return;
    const script = document.createElement('script');
    script.type = 'module';
    script.src = BEEQ_ESM_URL;
    script.dataset.beeqParentRuntime = BEEQ_ICONS_URL;
    document.head.appendChild(script);
  };
  const executeSnippetScripts = (root, runtimeWindow, previewRootArg, skipAttr) => {
    root.querySelectorAll('script').forEach(oldScript => {
      if (skipAttr && oldScript.hasAttribute(skipAttr)) return;
      if (oldScript.src) {
        const newScript = runtimeWindow.document.createElement('script');
        newScript.src = oldScript.src;
        oldScript.replaceWith(newScript);
        return;
      }
      runtimeWindow.Function('previewRoot', oldScript.textContent || '')(previewRootArg);
      oldScript.remove();
    });
  };
  const syncIframeMode = iframeDoc => {
    const root = document.documentElement;
    const explicitMode = root.getAttribute('bq-mode');
    const isDark = root.classList.contains('dark');
    const resolvedMode = explicitMode || (isDark ? 'dark' : 'light');
    iframeDoc.documentElement.setAttribute('bq-mode', resolvedMode);
    iframeDoc.body.setAttribute('bq-mode', resolvedMode);
  };
  useEffect(() => {
    if (mode === 'shadow') ensureParentBeeqRuntime();
  }, [mode]);
  useEffect(() => {
    const container = previewRef.current;
    if (!container) return;
    if (removePadding) container.style.padding = '0';
    container.innerHTML = '';
    if (mode === 'iframe') {
      const iframe = document.createElement('iframe');
      iframe.className = 'preview-iframe';
      iframe.style.width = '100%';
      iframe.style.border = '0';
      iframe.style.display = 'block';
      iframe.style.minHeight = height ?? '0px';
      iframe.setAttribute('title', 'Live code preview');
      iframe.setAttribute('loading', 'lazy');
      iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
      container.appendChild(iframe);
      const iframeDoc = iframe.contentDocument;
      const iframeWin = iframe.contentWindow;
      if (!iframeDoc || !iframeWin) return;
      iframeDoc.open();
      iframeDoc.write(['<!doctype html>', '<html>', '<head>', '  <meta charset="utf-8" />', '  <meta name="viewport" content="width=device-width, initial-scale=1" />', '  <style>html,body{margin:0;padding:0;min-height:100%;}</style>', `  <link rel="stylesheet" href="${BEEQ_CSS_URL}" />`, `  <script type="module" src="${BEEQ_ESM_URL}" data-beeq-iframe-runtime="${BEEQ_ICONS_URL}"></script>`, '</head>', '<body>', code, '</body>', '</html>'].join('\n'));
      iframeDoc.close();
      syncIframeMode(iframeDoc);
      const modeObserver = new MutationObserver(() => syncIframeMode(iframeDoc));
      modeObserver.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ['class', 'bq-mode']
      });
      executeSnippetScripts(iframeDoc, iframeWin, iframeDoc, 'data-beeq-iframe-runtime');
      return () => modeObserver.disconnect();
    }
    const shadowRoot = container.shadowRoot ?? container.attachShadow({
      mode: 'open'
    });
    if (!shadowRoot.adoptedStyleSheets.length) {
      const fixSheet = new CSSStyleSheet();
      fixSheet.replaceSync(`
        bq-dropdown::part(panel),
        bq-panel::part(panel),
        bq-select::part(panel),
        bq-date-picker::part(panel) { z-index: 9999; }
        bq-tooltip::part(panel) { position: absolute; }
      `);
      shadowRoot.adoptedStyleSheets = [fixSheet];
    }
    shadowRoot.innerHTML = [`<link rel="stylesheet" href="${BEEQ_CSS_URL}">`, code].join('');
    executeSnippetScripts(shadowRoot, window, shadowRoot);
    return undefined;
  }, [code, mode, height]);
  return <div className="code-live-preview not-prose">
      {}
      <div className="preview" ref={previewRef} style={{
    minHeight: height
  }} />

      {}
      {children && <div className="code">{children}</div>}
    </div>;
};

export const CardTile = ({title, href, imageLightSrc, imageDarkSrc, children, enableImgZoom}) => {
  if (!href) {
    return <div className="card-tile block font-normal group relative my-2 ring-2 ring-transparent rounded-2xl overflow-hidden w-full">
        {imageLightSrc && <img className="w-full m-0 block dark:hidden" src={imageLightSrc} alt={title} {...enableImgZoom ? {
      zoom: true
    } : {
      noZoom: true
    }} />}
        {imageDarkSrc && <img className="w-full m-0 hidden dark:block" src={imageDarkSrc} alt={title} {...enableImgZoom ? {
      zoom: true
    } : {
      noZoom: true
    }} />}
        {title && <h2 className="mt-4 mb-2 px-6 text-base font-semibold">{title}</h2>}
        <div className="px-6 pb-5">{children}</div>
      </div>;
  }
  return <a href={href} className="card-tile block font-normal group relative my-2 ring-2 ring-transparent rounded-2xl overflow-hidden w-full cursor-pointer">
      {imageLightSrc && <img className="w-full m-0 block dark:hidden" src={imageLightSrc} alt={title} noZoom />}
      {imageDarkSrc && <img className="w-full m-0 hidden dark:block" src={imageDarkSrc} alt={title} noZoom />}
      {title && <h2 className="mt-4 mb-2 px-6 text-base font-semibold">{title}</h2>}
      <div className="px-6 pb-5">{children}</div>
    </a>;
};

<Frame className="px-4 py-4" caption="Progress component overview">
  <img className="block dark:hidden" src="https://mintcdn.com/beeq/Z4ffKipt5yZIDQUT/components/images/progress/progress-overview-light.svg?fit=max&auto=format&n=Z4ffKipt5yZIDQUT&q=85&s=5f7dba74b8594491ed6b81b134ea8f5e" alt="BEEQ Progress component overview" width="250" height="265" data-path="components/images/progress/progress-overview-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/beeq/Z4ffKipt5yZIDQUT/components/images/progress/progress-overview-dark.svg?fit=max&auto=format&n=Z4ffKipt5yZIDQUT&q=85&s=e24b460b109b18915e3d97dc22c3eedb" alt="BEEQ Progress component overview" width="250" height="265" data-path="components/images/progress/progress-overview-dark.svg" />
</Frame>

Progress bars communicate the status of ongoing tasks such as downloads, uploads, installations, or any operation with measurable completion. They reduce uncertainty by showing how much work is done and how much remains.

<Note>
  Use a determinate progress bar when completion can be calculated against a known total. Use `indeterminate` only when the duration or completion cannot be determined.
</Note>

## When to use

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-up" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Use progress bars when
    </span>

    * The task has a measurable duration and a defined completion point
    * Real-time feedback helps users understand how long they need to wait
    * You need to communicate progress, completion, or error state visually
    * A spinner would feel too vague because the work can be quantified
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-down" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Do not use progress bars when
    </span>

    * The task completes instantly and no waiting feedback is needed
    * Progress cannot be tracked reliably and a determinate bar would be misleading
    * A spinner or loading skeleton is a better fit for the context
    * The bar would compete with the main content instead of supporting it
  </Card>
</CardGroup>

## Patterns

<CardGroup cols={2}>
  <Card title="With percentage">
    Show the progress value when users need a clear percentage in addition to the visual bar.
  </Card>

  <Card title="With tooltip">
    Use a tooltip when you want the progress value attached to the indicator instead of displayed beside the bar.
  </Card>

  <Card title="Determinate">
    Use a determinate progress bar when the task can be measured against a known completion point.
  </Card>

  <Card title="Indeterminate">
    Use an indeterminate progress bar when work is in progress but the exact completion point cannot be determined.
  </Card>

  <Card title="Top page progress bar">
    A progress bar can also appear at the top of the page to communicate loading or update status without interrupting the main content.
  </Card>
</CardGroup>

## Anatomy

<Frame className="px-4 py-4" caption="Progress component anatomy">
  <img className="block dark:hidden" src="https://mintcdn.com/beeq/Z4ffKipt5yZIDQUT/components/images/progress/progress-anatomy-light.svg?fit=max&auto=format&n=Z4ffKipt5yZIDQUT&q=85&s=2a586ed75c3a889db5b191399f9c0436" alt="BEEQ Progress component anatomy" width="322" height="155" data-path="components/images/progress/progress-anatomy-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/beeq/Z4ffKipt5yZIDQUT/components/images/progress/progress-anatomy-dark.svg?fit=max&auto=format&n=Z4ffKipt5yZIDQUT&q=85&s=af31c0ccf199e2bc05dbca6d470031c2" alt="BEEQ Progress component anatomy" width="322" height="155" data-path="components/images/progress/progress-anatomy-dark.svg" />
</Frame>

The progress component is made up of the track, the filled indicator, and the progress value when it is displayed.

| Part  | Element       | Description                                                                |
| ----- | ------------- | -------------------------------------------------------------------------- |
| **1** | Bar indicator | The filled portion showing the current progress value                      |
| **2** | Track         | The background rail representing the full available range                  |
| **3** | Value         | The percentage detail shown when the progress value is exposed to the user |

## Design guidelines

Choose the progress treatment that matches how precise the feedback needs to be.

<CardGroup cols={2}>
  <CardTile title="Show a percentage when precision matters" imageLightSrc="/components/images/progress/progress-percentage-guidance-light.svg" imageDarkSrc="/components/images/progress/progress-percentage-guidance-dark.svg">
    Add `label` or `enable-tooltip` when users need a clear numeric indication of how much work remains.
  </CardTile>

  <CardTile title="Pair status changes with context" imageLightSrc="/components/images/progress/progress-status-guidance-light.svg" imageDarkSrc="/components/images/progress/progress-status-guidance-dark.svg">
    Color changes such as `type="error"` should always be supported by nearby text that explains what happened.
  </CardTile>
</CardGroup>

<Steps>
  <Step title="Choose the feedback type">
    Start with a determinate bar whenever progress can be measured. Switch to `indeterminate` only when the task is active but cannot be quantified.
  </Step>

  <Step title="Choose the emphasis">
    Use `medium` thickness by default. Use `large` only when the progress bar needs stronger visual emphasis in a prominent area.
  </Step>

  <Step title="Choose the detail level">
    Add `label` for persistent percentage text or `enable-tooltip` when you want the value attached to the indicator instead.
  </Step>
</Steps>

<Note>
  When `indeterminate` is enabled, `label` and `enable-tooltip` do not render a percentage, because the component cannot represent a specific completion value.
</Note>

## Usage

### Default

Use the default progress bar for general task tracking when the process has a measurable completion point.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: center !important;
  gap: var(--bq-spacing-m) !important;
}

bq-progress {
  width: 250px;
}
</style>

<bq-progress value="25"></bq-progress>
<bq-progress value="50"></bq-progress>
<bq-progress value="75"></bq-progress>
<bq-progress value="100"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress value="25"></bq-progress>
    <bq-progress value="50"></bq-progress>
    <bq-progress value="75"></bq-progress>
    <bq-progress value="100"></bq-progress>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <>
      <BqProgress value={25} />
      <BqProgress value={50} />
      <BqProgress value={75} />
      <BqProgress value={100} />
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `
        <bq-progress value="25"></bq-progress>
        <bq-progress value="50"></bq-progress>
        <bq-progress value="75"></bq-progress>
        <bq-progress value="100"></bq-progress>
      `
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress :value="25" />
      <BqProgress :value="50" />
      <BqProgress :value="75" />
      <BqProgress :value="100" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Options

### Large thickness

Use `thickness="large"` to increase the visual weight of the progress bar in more prominent layouts.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: center !important;
  gap: var(--bq-spacing-m) !important;
}

bq-progress {
  width: 250px;
}
</style>

<bq-progress value="30"></bq-progress>
<bq-progress thickness="large" value="30"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress value="30"></bq-progress>
    <bq-progress thickness="large" value="30"></bq-progress>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <>
      <BqProgress value={30} />
      <BqProgress thickness="large" value={30} />
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `
        <bq-progress value="30"></bq-progress>
        <bq-progress thickness="large" value="30"></bq-progress>
      `
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress :value="30" />
      <BqProgress thickness="large" :value="30" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Error

Use `type="error"` to communicate that a process failed or needs attention.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
bq-progress {
  width: 250px;
}
</style>

<bq-progress type="error" value="30"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress type="error" value="30"></bq-progress>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <BqProgress type="error" value={30} />
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `<bq-progress type="error" value="30"></bq-progress>`
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress type="error" :value="30" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

<Tip>
  Always pair a color change with a contextual message. Color alone is not enough to communicate an error state clearly to all users.
</Tip>

### Border shape

Use `border-shape="square"` when you want a straighter edge treatment. The default is `rounded`.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: center !important;
  gap: var(--bq-spacing-m) !important;
}

bq-progress {
  width: 250px;
}
</style>

<bq-progress value="80"></bq-progress>
<bq-progress border-shape="square" value="80"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress value="80"></bq-progress>
    <bq-progress border-shape="square" value="80"></bq-progress>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <>
      <BqProgress value={80} />
      <BqProgress borderShape="square" value={80} />
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `
        <bq-progress value="80"></bq-progress>
        <bq-progress border-shape="square" value="80"></bq-progress>
      `
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress :value="80" />
      <BqProgress borderShape="square" :value="80" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### With label

Add `label` to display a persistent numeric percentage beside the bar.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: center !important;
  gap: var(--bq-spacing-m) !important;
}

bq-progress {
  width: 250px;
}
</style>

<bq-progress label value="25"></bq-progress>
<bq-progress label value="50"></bq-progress>
<bq-progress label value="75"></bq-progress>
<bq-progress label value="100"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress label value="25"></bq-progress>
    <bq-progress label value="50"></bq-progress>
    <bq-progress label value="75"></bq-progress>
    <bq-progress label value="100"></bq-progress>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <>
      <BqProgress label value={25} />
      <BqProgress label value={50} />
      <BqProgress label value={75} />
      <BqProgress label value={100} />
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `
        <bq-progress label value="25"></bq-progress>
        <bq-progress label value="50"></bq-progress>
        <bq-progress label value="75"></bq-progress>
        <bq-progress label value="100"></bq-progress>
      `
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress label :value="25" />
      <BqProgress label :value="50" />
      <BqProgress label :value="75" />
      <BqProgress label :value="100" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### With tooltip

Add `enable-tooltip` to show the current percentage at the indicator. In the current component implementation, the tooltip stays visible while the option is enabled.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: center !important;
  gap: var(--bq-spacing-m) !important;
  padding-block: var(--bq-spacing-xl) !important;
}

bq-progress {
  width: 250px;
}
</style>

<bq-progress enable-tooltip value="25"></bq-progress>
<bq-progress enable-tooltip value="50"></bq-progress>
<bq-progress enable-tooltip value="75"></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress enable-tooltip value="25"></bq-progress>
    <bq-progress enable-tooltip value="50"></bq-progress>
    <bq-progress enable-tooltip value="75"></bq-progress>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <>
      <BqProgress enableTooltip value={25} />
      <BqProgress enableTooltip value={50} />
      <BqProgress enableTooltip value={75} />
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `
        <bq-progress enable-tooltip value="25"></bq-progress>
        <bq-progress enable-tooltip value="50"></bq-progress>
        <bq-progress enable-tooltip value="75"></bq-progress>
      `
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress enableTooltip :value="25" />
      <BqProgress enableTooltip :value="50" />
      <BqProgress enableTooltip :value="75" />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

<Tip>
  Choose `enable-tooltip` when you want the percentage anchored to the indicator instead of rendered as a separate inline label.
</Tip>

### Indeterminate

Use `indeterminate` when the task is active but the exact completion point cannot be measured.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
bq-progress {
  width: 250px;
}
</style>

<bq-progress indeterminate></bq-progress>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-progress indeterminate></bq-progress>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqProgress } from "@beeq/react";

    <BqProgress indeterminate />
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqProgress } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqProgress],
      template: `<bq-progress indeterminate></bq-progress>`
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqProgress } from "@beeq/vue";
    </script>

    <template>
      <BqProgress indeterminate />
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Best practices

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Place descriptive text close to the progress bar so people immediately understand what is being tracked.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not embed text inside the bar itself. It becomes unreadable at low progress values and is harder to interpret accessibly.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Use `label` or `enable-tooltip` when users need a precise sense of how much work remains.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not use a determinate progress bar when progress cannot actually be measured. That creates false certainty.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Pair `type="error"` with a visible message so users who cannot perceive color still understand the failure.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not rely on color alone to communicate error state. Not all users perceive color distinctions.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Use `indeterminate` only when the duration genuinely cannot be measured. Switch to a determinate bar as soon as progress can be tracked.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not use an indeterminate bar as a substitute when a determinate bar is technically possible. It creates unnecessary uncertainty.
  </Card>
</CardGroup>

## Accessibility

* **Built-in progress semantics** — the component renders a native `<progress>` element inside its shadow DOM, which browsers expose as `role="progressbar"` with `aria-valuenow`, `aria-valuemin="0"`, and `aria-valuemax="100"` automatically. Assistive technology reads the current value without additional markup.
* **Indeterminate state** — when `indeterminate` is `true`, the native element has no `value` attribute, and assistive technology announces it as an indeterminate progress bar.
* **Provide task context**: add a visible label or nearby text that explains what operation the progress bar is tracking.
* **Do not rely on color alone**: pair `type="error"` with a visible message so the failure state is understandable without color perception.
* **Use percentage only when it helps**: `label` or `enable-tooltip` improves clarity when precise status matters, but it is not required for every short or self-explanatory task.
* **Be careful with motion**: if indeterminate animation is distracting in your application, respect `prefers-reduced-motion` at the app level.

## API reference

### Properties

| Property        | Attribute        | Description                                                                 | Type                      | Default     |
| --------------- | ---------------- | --------------------------------------------------------------------------- | ------------------------- | ----------- |
| `borderShape`   | `border-shape`   | Sets the border style of the progress bar                                   | `"rounded"` \| `"square"` | `"rounded"` |
| `enableTooltip` | `enable-tooltip` | If `true`, a tooltip showing the current value is rendered at the indicator | `boolean`                 | `false`     |
| `indeterminate` | `indeterminate`  | If `true`, the indeterminate animation is shown and `value` is ignored      | `boolean`                 | `false`     |
| `label`         | `label`          | If `true`, a percentage label is rendered beside the bar                    | `boolean`                 | `false`     |
| `thickness`     | `thickness`      | Controls the height of the bar                                              | `"medium"` \| `"large"`   | `"medium"`  |
| `type`          | `type`           | Sets the visual type of the progress bar                                    | `"default"` \| `"error"`  | `"default"` |
| `value`         | `value`          | The current progress value, clamped between `0` and `100`                   | `number`                  | `0`         |

### Shadow parts

| Part            | Description                                                           |
| --------------- | --------------------------------------------------------------------- |
| `base`          | The base container for the internal `bq-tooltip` component            |
| `indeterminate` | The `<div>` container that holds the animated indeterminate indicator |
| `label`         | The `<div>` container that holds the label value in percentage        |
| `panel`         | The container holding the tooltip content                             |
| `progress`      | The `<div>` container that holds the native `<progress>` element      |
| `progress-bar`  | The native `<progress>` element                                       |
| `trigger`       | The element that triggers the internal tooltip placement              |
| `wrapper`       | The component wrapper container inside the shadow DOM                 |

### CSS custom properties

| Variable                                | Description                                          | Default                   |
| --------------------------------------- | ---------------------------------------------------- | ------------------------- |
| `--bq-progress-bar--height`             | The progress bar height                              | `0.25rem`                 |
| `--bq-progress-bar--indeterminateWidth` | The width of the moving indicator when indeterminate | `25%`                     |
| `--bq-progress-bar--indicatorColor`     | The filled indicator color                           | `var(--bq-ui--brand)`     |
| `--bq-progress-bar--trackColor`         | The track color                                      | `var(--bq-ui--secondary)` |

<Tip>
  Learn more about [styling with shadow parts](/guides/styles#component-shadow-dom-parts) and [CSS custom properties](/guides/styles#global-css-custom-properties).
</Tip>

## Resources

<CardGroup cols={2}>
  <Card horizontal title="Interactive playground" icon="code" href="https://storybook.beeq.design/?path=/story/components-progress--default">
    Explore progress bar examples and states in Storybook.
  </Card>

  <Card horizontal title="Source code" icon="github" href="https://github.com/Endava/BEEQ/tree/main/packages/beeq/src/components/progress">
    Browse the component implementation, styles, and tests on GitHub.
  </Card>
</CardGroup>
