---
title: Spinner
description: >-
Use the Spinner component to notify customers that their action is being
processed, typically when sending or receiving data from a server.
api_version: 2025-07
api_name: customer-account-ui-extensions
source_url:
html: >-
https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/feedback-and-status-indicators/spinner
md: >-
https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/feedback-and-status-indicators/spinner.md
---
Migrate to Polaris
Version 2025-07 is the last API version to support React-based UI components. Later versions use [web components](https://shopify.dev/docs/api/customer-account-ui-extensions/latest/polaris-web-components), native UI elements with built-in accessibility, better performance, and consistent styling with [Shopify's design system](https://shopify.dev/docs/apps/design). Check out the [migration guide](https://shopify.dev/docs/apps/build/customer-accounts/migrate-to-web-components) to upgrade your extension.
# Spinner
Use the Spinner component to notify customers that their action is being processed. Spinners are typically used for page or section loading states when sending or receiving data from a server.
Spinners support multiple sizes and an `appearance` property to match the surrounding content. For operations with a known duration, use [Progress](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/feedback-and-status-indicators/progress) instead.
### Support Targets (25)
### Supported targets
* CustomerAccount::KitchenSink
* [customer-account.footer.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/footer#footer-render-after-)
* [customer-account.order-index.announcement.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-targets)
* [customer-account.order-index.block.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-block-)
* [customer-account.order-status.announcement.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-announcement-)
* [customer-account.order-status.block.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-block-)
* [customer-account.order-status.cart-line-item.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-item-render-after-)
* [customer-account.order-status.cart-line-list.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-list-render-after-)
* [customer-account.order-status.customer-information.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#customer-information-render-after-)
* [customer-account.order-status.fulfillment-details.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#fulfillment-status-targets)
* [customer-account.order-status.payment-details.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#payments-and-returns-targets)
* [customer-account.order-status.return-details.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#return-details-render-after-)
* [customer-account.order-status.unfulfilled-items.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#unfulfilled-items-render-after-)
* [customer-account.order.action.menu-item.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-menu-item-)
* [customer-account.order.action.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-)
* [customer-account.order.page.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#order-specific-full-page-)
* [customer-account.page.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#customer-account-full-page-)
* [customer-account.profile.addresses.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-page-default-targets-)
* [customer-account.profile.announcement.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#announcement-)
* [customer-account.profile.block.render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-block-)
* [customer-account.profile.company-details.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#profile-page-b2b-targets-)
* [customer-account.profile.company-location-addresses.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-addresses-render-after-)
* [customer-account.profile.company-location-payment.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-payment-render-after-)
* [customer-account.profile.company-location-staff.render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-staff-render-after-)
* customer-account.profile.payment.render-after
#### Use cases
* **Page-level loading**: Show a spinner while the extension fetches initial data from an API.
* **Section refresh**: Indicate that a specific section is refreshing, such as reloading subscription details after an update.
* **Async operation feedback**: Communicate that a background process is running, like processing a return request.
* **Content placeholder**: Display a spinner in place of content that hasn't loaded yet.
***
## Properties
Configure the following properties on the Spinner component.
* **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.
* **appearance**
**'accent' | 'monochrome'**
**Default: 'accent'**
The visual appearance of the spinner icon.
* `accent`: Uses the accent color to convey emphasis and draw attention.
* `monochrome`: Inherits the color of its parent element.
* **id**
**string**
A unique identifier for the component. Use this to target the component in scripts or stylesheets, or to distinguish it from other instances of the same component.
* **size**
**'extraSmall' | 'small' | 'large' | 'base' | 'fill'**
**Default: 'base'**
The size of the spinner icon.
* `extraSmall`: The smallest size for tight spaces or inline indicators.
* `small`: A compact size for secondary loading states.
* `base`: The default size, suitable for most use cases.
* `large`: A larger size for more prominent loading states.
* `fill`: Expands to fill the available space.
***
## Examples
### Show a loading indicator
Display a basic spinner to indicate that content is loading. Without an `accessibilityLabel`, the spinner renders an animated indicator for all customers.
## Show a loading indicator

## Show a loading indicator
##### React
```tsx
import {
reactExtension,
Spinner,
} from '@shopify/ui-extensions-react/customer-account';
export default reactExtension(
'customer-account.page.render',
() => ,
);
function Extension() {
return ;
}
```
##### JS
```js
import {extension, Spinner} from '@shopify/ui-extensions/customer-account';
export default extension('customer-account.page.render', (root) => {
const spinner = root.createComponent(Spinner);
root.appendChild(spinner);
});
```
### Display a labeled loading state
Pair a spinner with text to describe what's loading. This example centers a spinner above a "Loading order details..." message so customers know what to expect.
## Display a labeled loading state
##### React
```tsx
import {
reactExtension,
BlockStack,
Spinner,
Text,
} from '@shopify/ui-extensions-react/customer-account';
export default reactExtension(
'customer-account.page.render',
() => ,
);
function Extension() {
return (
Loading order details...
);
}
```
##### JS
```js
import {
extension,
BlockStack,
Spinner,
Text,
} from '@shopify/ui-extensions/customer-account';
export default extension('customer-account.page.render', (root) => {
const container = root.createComponent(
BlockStack,
{inlineAlignment: 'center', spacing: 'base'},
[
root.createComponent(Spinner, {
accessibilityLabel: 'Loading order details',
}),
root.createComponent(
Text,
{appearance: 'subdued'},
'Loading order details...',
),
],
);
root.appendChild(container);
});
```
### Use a monochrome spinner
Set `appearance="monochrome"` so the spinner takes the color of its parent, blending with surrounding text. This example shows a small monochrome spinner inline with a status message.
## Use a monochrome spinner
##### React
```tsx
import {
reactExtension,
InlineStack,
Spinner,
Text,
} from '@shopify/ui-extensions-react/customer-account';
export default reactExtension(
'customer-account.page.render',
() => ,
);
function Extension() {
return (
Refreshing your subscription...
);
}
```
##### JS
```js
import {
extension,
InlineStack,
Spinner,
Text,
} from '@shopify/ui-extensions/customer-account';
export default extension('customer-account.page.render', (root) => {
const container = root.createComponent(
InlineStack,
{spacing: 'base', blockAlignment: 'center'},
[
root.createComponent(Spinner, {
size: 'small',
appearance: 'monochrome',
accessibilityLabel: 'Refreshing',
}),
root.createComponent(
Text,
{appearance: 'subdued'},
'Refreshing your subscription...',
),
],
);
root.appendChild(container);
});
```
***
## Best practices
* **Always provide an accessibility label**: Set `accessibilityLabel` so screen readers can announce what's loading. Without it, the spinner is just an animated graphic with no context.
* **Use spinners for page or section loading, not buttons**: For button loading states, use the button's built-in loading property instead.
* **Pair with descriptive text**: Spinners alone don't explain what's happening. Add nearby text that describes the operation in progress.
* **Use monochrome to blend with content**: Set `appearance="monochrome"` when the spinner should match the color of its parent element rather than using the default accent color.
***
## Limitations
* The Spinner component doesn't include built-in text. Pair it with layout and text components to describe the loading state.
* Customers who prefer reduced motion see a static text label instead of the animated indicator, but only if `accessibilityLabel` is set. Without it, the animated indicator is shown to all customers.
* Spinner sizes are limited to the predefined set (`extraSmall`, `small`, `base`, `large`, `fill`). Custom sizes aren't supported.
***