--- title: SkeletonImage description: >- The SkeletonImage component provides a low-fidelity placeholder representation of an image before it appears on the page. Use SkeletonImage to maintain layout stability and reduce perceived loading time while images are being fetched. 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/media-and-visuals/skeletonimage md: >- https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/media-and-visuals/skeletonimage.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. # SkeletonImage The SkeletonImage component provides a low-fidelity placeholder representation of an image before it appears on the page. Use SkeletonImage to maintain layout stability and reduce perceived loading time while images are being fetched. Skeleton images support custom dimensions and aspect ratios to match the final loaded content. Combine with [SkeletonText](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/typography-and-content/skeletontext) and [SkeletonTextBlock](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/typography-and-content/skeletontextblock) for complete loading states. ### Support Targets (25) ### Supported targets * Customer​Account::Kitchen​Sink * [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 * **Image loading states**: Show a placeholder while product images load from remote URLs. * **Layout stability**: Prevent content from shifting when images load by reserving the correct amount of space. * **Progressive loading**: Create smooth transitions from loading skeleton to final content. * **List placeholders**: Display skeleton thumbnails in product lists while data is being fetched. * **Responsive placeholders**: Use [StyleHelper](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/layout-and-structure/stylehelper) to adjust placeholder dimensions at different viewport sizes. *** ## Properties Configure the following properties on the SkeletonImage component. * **aspectRatio** **number** The aspect ratio to display the skeleton at (fills the width of the parent container and sets the height accordingly). Use this to reserve the correct space for an image before it loads, preventing content jumping. * **blockSize** **MaybeResponsiveConditionalStyle\** The block size (height in horizontal writing modes) of the skeleton placeholder. * `number`: The size in pixels. * `` `${number}%` ``: The size as a percentage of the parent container's block size. * `fill`: Takes all the available space. Learn more about the [block-size](https://developer.mozilla.org/en-US/docs/Web/CSS/block-size) property. * **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. * **inlineSize** **MaybeResponsiveConditionalStyle\** The inline size (width in horizontal writing modes) of the skeleton placeholder. * `number`: The size in pixels. * `` `${number}%` ``: The size as a percentage of the parent container's inline size. * `fill`: Takes all the available space. Learn more about the [inline-size](https://developer.mozilla.org/en-US/docs/Web/CSS/inline-size) property. ### MaybeResponsiveConditionalStyle A type that represents a value that can be a conditional style. The conditions are based on the viewport size. We highly recommend using the \`Style\` helper which simplifies the creation of conditional styles. ```ts T | ConditionalStyle ``` ### ConditionalStyle A conditional style definition that maps one or more conditions to different values. The \`default\` value is used as a fallback when none of the conditions in \`conditionals\` are satisfied. * conditionals An array of conditional values. ```ts ConditionalValue[] ``` * default The default value applied when none of the conditional values specified in \`conditionals\` are met. ```ts T ``` ### ConditionalValue A single conditional branch that pairs a set of conditions with the value to apply when those conditions are met. * conditions The conditions that must be met for the value to be applied. At least one condition must be specified. ```ts AcceptedConditions ``` * value The value that will be applied if the conditions are met. ```ts T ``` ### ViewportSizeCondition A condition that targets layouts based on the inline size (width in horizontal writing modes) of the viewport. * viewportInlineSize The minimum viewport inline size that the condition must match. ```ts { min: T; } ``` *** ## Examples ### Display a skeleton placeholder Show a placeholder while an image loads. This example renders a 300x300 pixel skeleton image that reserves space for the final content. ## Display a skeleton placeholder ![A gray skeleton placeholder representing a loading image.](https://shopify.dev/assets/assets/images/templated-apis-screenshots/checkout-ui-extensions/2025-07/skeletonimage-default-FXO81Xcs.png) ## Display a skeleton placeholder ##### React ```tsx import { reactExtension, SkeletonImage, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.page.render', () => , ); function Extension() { return ( ); } ``` ##### JS ```js import {extension, SkeletonImage} from '@shopify/ui-extensions/customer-account'; export default extension('customer-account.page.render', (root) => { const skeletonImage = root.createComponent(SkeletonImage, { inlineSize: 300, blockSize: 300, }); root.appendChild(skeletonImage); }); ``` ### Prevent layout shifts during loading Incorporate skeleton loaders that match the size and position of the content during loading. This provides a seamless transition from skeleton loaders to the content and prevents layout shift when the resulting content loads. ## Prevent layout shifts during loading ##### React ```tsx import { reactExtension, View, BlockStack, InlineLayout, SkeletonImage, Image, Icon, SkeletonText, Text, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); export const ProductThumbnail = ({ source = 'https://yourawesomeimage.com', }) => ( {source ? ( ) : ( )} ); export const LoadingStateSkeletons = () => { const loading = true; const [item1, item2] = [ { title: 'Felipe Toledo WildFire', variantTitle: 'Medium', price: '$330.00', }, { title: 'Roller', variantTitle: 'Medium', price: '$248.00', }, ]; const itemInfo = ({title, variantTitle}) => loading ? ( <> {title} {variantTitle} ) : ( <> {title} {variantTitle} ); const order = (item) => ( {loading ? ( ) : ( )} {itemInfo(item)} {loading ? ( {item.price} ) : ( {item.price} )} ); return ( {order(item1)} {order(item2)} ); }; ``` ##### JS ```js import { extension, BlockStack, View, InlineLayout, Image, Icon, Text, SkeletonImage, SkeletonText, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root) => { const source = 'https://yourawesomeimage.com'; const loading = true; const [item1, item2] = [ { title: 'Felipe Toledo WildFire', variantTitle: 'Medium', price: '$330.00', }, { title: 'Roller', variantTitle: 'Medium', price: '$248.00', }, ]; const thumbnail = root.createComponent( View, { minBlockSize: 64, cornerRadius: 'large', maxInlineSize: 64, minInlineSize: 64, border: 'base', }, [ source ? root.createComponent(Image, { fit: 'cover', aspectRatio: 1, source, cornerRadius: 'large', }) : root.createComponent( View, {maxInlineSize: 33}, [ root.createComponent(Icon, { source: 'camera', size: 'fill', }), ], ), ], ); const itemInfo = ({title, variantTitle}) => root.createComponent( BlockStack, { spacing: 'extraTight', }, [ loading ? (root.createComponent( SkeletonText, {}, title, ), root.createComponent( SkeletonText, {}, variantTitle, )) : (root.createComponent( Text, {}, title, ), root.createComponent( Text, {}, variantTitle, )), ], ); const order = (item) => root.createComponent( InlineLayout, { columns: ['auto', 'fill', 'auto'], spacing: 'base', blockAlignment: 'center', }, [ loading ? root.createComponent( SkeletonImage, { blockSize: 64, inlineSize: 64, }, ) : thumbnail, itemInfo(item), loading ? root.createComponent( SkeletonText, {}, item.price, ) : root.createComponent( Text, {}, item.price, ), ], ); const view = root.createComponent( View, { maxInlineSize: 400, }, [ root.createComponent(BlockStack, {}, [ order(item1), order(item2), ]), ], ); root.appendChild(view); }, ); ``` ### Set custom dimensions Create skeleton placeholders at different sizes and aspect ratios. This example shows three skeleton images with varying dimensions to demonstrate how `inlineSize`, `blockSize`, and `aspectRatio` control the placeholder shape. ## Set custom dimensions ##### React ```tsx import { reactExtension, SkeletonImage, InlineStack, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.page.render', () => , ); function Extension() { return ( ); } ``` ##### JS ```js import {extension, SkeletonImage, InlineStack} from '@shopify/ui-extensions/customer-account'; export default extension('customer-account.page.render', (root) => { const row = root.createComponent(InlineStack, {spacing: 'base'}); row.append(root.createComponent(SkeletonImage, {inlineSize: 64, blockSize: 64})); row.append(root.createComponent(SkeletonImage, {inlineSize: 200, blockSize: 150})); row.append(root.createComponent(SkeletonImage, {inlineSize: 100, aspectRatio: 16 / 9})); root.append(row); }); ``` *** ## Best practices * **Match the skeleton to the final image size**: Set the skeleton dimensions to closely approximate the loaded image so the layout doesn't shift when the real image appears. * **Use for content that takes time to load**: Display skeleton images when fetching remote images or processing data. Don't use them for content that's immediately available. * **Combine with other skeleton components**: Use skeleton images alongside [SkeletonText](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/typography-and-content/skeletontext) and [SkeletonTextBlock](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/ui-components/typography-and-content/skeletontextblock) to create a cohesive loading experience. *** ## Limitations * The skeleton image renders as a static placeholder. Animated shimmer effects aren't configurable. * The component doesn't automatically transition to the loaded image. You need to handle the loading state and swap the skeleton for the real image in your extension code. ***