Skip to main content
Migrate to Polaris

Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the migration guide to upgrade your extension.

ProgressIndicator

The ProgressIndicator component displays an animated spinner to communicate that content is loading or an action is being processed. Use ProgressIndicator to provide visual feedback during asynchronous operations like data fetching, form submission, or background processing.

ProgressIndicator supports a range of sizes from compact inline indicators to larger full-section spinners, so it can be placed alongside other components or used as a standalone loading state.

Support
Targets (46)

Supported targets


Props for the ProgressIndicator component, which renders a visual cue (such as a spinner) to communicate that a process is underway. Use this component to reassure users that content is loading or an action is being processed.

required

The size of the progress indicator. This prop is required and determines how large the indicator renders. Use smaller sizes for inline or compact placements, and larger sizes for prominent loading states.

Anchor to accessibilityLabel
accessibilityLabel
string

A label that describes the purpose or contents of the element. When set, it will be announced to users using assistive technologies and will provide them with more context. When set, any children or label supplied won't be announced to screen readers.

string

A unique identifier for the element.

'inherit' | 'default'
Default: 'default'

The color of the progress indicator.

  • inherit: Takes the color value from its parent, giving the progress indicator a monochrome appearance. This is useful when you want the indicator to blend with surrounding text or icons.
  • default: Uses the standard progress indicator color.
Anchor to variant
variant
'spinner'
Default: 'spinner'

The visual style of the progress indicator.

  • spinner: Renders a circular spinning animation to indicate an indeterminate loading state.

Anchor to Show loading during API queryShow loading during API query

Show a loading indicator while querying product data from the GraphQL Admin API, then replace it with the results. This example uses ProgressIndicator with size and accessibilityLabel props during the query, then displays the product title and inventory count.

Show loading during API query

Show a loading indicator while querying product data from the [GraphQL Admin API](/docs/api/admin-graphql/), then replace it with the results. This example uses `ProgressIndicator` with `size` and `accessibilityLabel` props during the query, then displays the product title and inventory count.

Show loading during API query

import {useState, useEffect} from 'react';
import {reactExtension, useApi, ProgressIndicator, Text, BlockStack} from '@shopify/ui-extensions-react/admin';

function App() {
const {data, query} = useApi('admin.product-details.block.render');
const productId = data.selected[0]?.id;
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
query(
`query Product($id: ID!) {
product(id: $id) { title totalInventory }
}`,
{variables: {id: productId}},
).then((result) => {
setProduct(result?.data?.product);
setLoading(false);
});
}, [productId, query]);

return (
<BlockStack>
{loading ? (
<ProgressIndicator
size="small-200"
accessibilityLabel="Loading product data"
/>
) : product ? (
<>
<Text fontWeight="bold">{product.title}</Text>
<Text>Total inventory: {product.totalInventory} units</Text>
</>
) : null}
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);
import {extension, ProgressIndicator, Text, BlockStack} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.block.render',
async (root, api) => {
const {data, query} = api;
const productId = data.selected[0]?.id;

const stack = root.createComponent(BlockStack);

const loader = root.createComponent(ProgressIndicator, {
size: 'small-200',
accessibilityLabel: 'Loading product data',
});
stack.appendChild(loader);
root.appendChild(stack);

const result = await query(
`query Product($id: ID!) {
product(id: $id) { title totalInventory }
}`,
{variables: {id: productId}},
);

stack.removeChild(loader);

const product = result?.data?.product;
if (product) {
const title = root.createComponent(
Text,
{fontWeight: 'bold'},
product.title,
);
const inventory = root.createComponent(
Text,
{},
`Total inventory: ${product.totalInventory} units`,
);
stack.appendChild(title);
stack.appendChild(inventory);
}
},
);

Anchor to Display sync progress in action modalDisplay sync progress in action modal

Show a prominent loading indicator while a sync is in progress inside an action modal. This example pairs a base-sized indicator with a status message and a cancel Button, keeping merchants informed and in control.

Display sync progress in action modal

import {reactExtension, ProgressIndicator, Text, Button, BlockStack, InlineStack} from '@shopify/ui-extensions-react/admin';

function App() {
const {data, close} = useApi('admin.product-details.action.render');

return (
<BlockStack>
<Text>Syncing product data to your warehouse system...</Text>
<InlineStack>
<ProgressIndicator
size="base"
accessibilityLabel="Syncing in progress"
/>
</InlineStack>
<Button variant="tertiary" onPress={() => close()}>
Cancel
</Button>
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.action.render',
() => <App />,
);
import {extension, ProgressIndicator, Text, Button, BlockStack, InlineStack} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.action.render',
(root, api) => {
const {data, close} = api;

const stack = root.createComponent(BlockStack);

const message = root.createComponent(
Text,
{},
'Syncing product data to your warehouse system...',
);

const spinnerRow = root.createComponent(InlineStack);
const spinner = root.createComponent(ProgressIndicator, {
size: 'base',
accessibilityLabel: 'Syncing in progress',
});
spinnerRow.appendChild(spinner);

const cancelButton = root.createComponent(
Button,
{
variant: 'tertiary',
onPress: () => close(),
},
'Cancel',
);

stack.appendChild(message);
stack.appendChild(spinnerRow);
stack.appendChild(cancelButton);
root.appendChild(stack);
},
);

Anchor to Add inline loading indicatorAdd inline loading indicator

Place a compact small-300 spinner inline with status text using tone="inherit" to match the surrounding text color. This example renders the indicator alongside a description inside an InlineStack, creating a subtle loading cue.

Add inline loading indicator

import {reactExtension, ProgressIndicator, Text, InlineStack, BlockStack} from '@shopify/ui-extensions-react/admin';

function App() {

return (
<BlockStack>
<Text fontWeight="bold">Checking eligibility...</Text>
<InlineStack>
<ProgressIndicator
size="small-300"
tone="inherit"
accessibilityLabel="Checking product eligibility"
/>
<Text>Verifying product meets marketplace requirements</Text>
</InlineStack>
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);
import {extension, ProgressIndicator, Text, InlineStack, BlockStack} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.block.render',
(root) => {

const stack = root.createComponent(BlockStack);

const heading = root.createComponent(
Text,
{fontWeight: 'bold'},
'Checking eligibility...',
);

const row = root.createComponent(InlineStack);

const indicator = root.createComponent(ProgressIndicator, {
size: 'small-300',
tone: 'inherit',
accessibilityLabel: 'Checking product eligibility',
});

const label = root.createComponent(
Text,
{},
'Verifying product meets marketplace requirements',
);

row.appendChild(indicator);
row.appendChild(label);

stack.appendChild(heading);
stack.appendChild(row);
root.appendChild(stack);
},
);

  • Match the size to the context: Use smaller sizes for inline indicators next to buttons or fields, and larger sizes for full-section or full-page loading states.
  • Show spinners only when needed: Display the ProgressIndicator only while an operation is in progress. Remove it immediately when loading completes or an error occurs. Avoid leaving a spinner visible indefinitely.

  • ProgressIndicator supports only the spinner variant. There is no progress bar or determinate progress indicator available.
  • ProgressIndicator doesn't communicate progress percentage or estimated time remaining. For operations where progress can be measured, consider pairing the spinner with a text description of the current status.
  • The spinner animation can't be paused or customized. It always displays the same continuous rotation animation.

Was this page helpful?