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.

Skeleton image

The SkeletonImage component is used to provide a low fidelity representation of an image before it appears on the page.

Support
Targets (50)

Supported targets


Anchor to aspectRatio
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.

Anchor to blockSize
blockSize
<number | `${number}%` | 'fill'>

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

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.

Anchor to inlineSize
inlineSize
<number | `${number}%` | 'fill'>

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


Basic SkeletonImage

Example

Basic SkeletonImage

import {
reactExtension,
SkeletonImage,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<SkeletonImage
inlineSize={300}
blockSize={300}
/>
);
}
import {extension, SkeletonImage} from '@shopify/ui-extensions/checkout';

export default extension('purchase.checkout.block.render', (root) => {
const skeletonImage = root.createComponent(SkeletonImage, {
inlineSize: 300,
blockSize: 300,
});

root.appendChild(skeletonImage);
});

Anchor to Using skeleton loaders to prevent layout shifts on content load.Using skeleton loaders to prevent layout shifts on content load.

When adding content to a layout, incorporate the SkeletonImage component so it renders the approximate size and position of the content during loading. This will provide a seamless transition from skeleton loaders to the content, and prevent any layout shift when the resulting content loads.

Using skeleton loaders to prevent layout shifts on content load.

When adding content to a layout, incorporate the SkeletonImage component so it renders the approximate size and position of the content during loading. This will provide a seamless transition from skeleton loaders to the content, and prevent any layout shift when the resulting content loads.

Using skeleton loaders to prevent layout shifts on content load.

import {
reactExtension,
View,
BlockStack,
InlineLayout,
SkeletonImage,
Image,
Icon,
SkeletonText,
Text,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <LoadingStateSkeletons />,
);

export const ProductThumbnail = ({
source = 'https://yourawesomeimage.com',
}) => (
<View
minBlockSize={64}
cornerRadius="large"
maxInlineSize={64}
minInlineSize={64}
border="base"
>
{source ? (
<Image
fit="cover"
aspectRatio={1}
source={source}
cornerRadius="large"
/>
) : (
<View maxInlineSize={33}>
<Icon source="camera" size="fill" />
</View>
)}
</View>
);
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 ? (
<>
<SkeletonText>{title}</SkeletonText>
<SkeletonText>
{variantTitle}
</SkeletonText>
</>
) : (
<>
<Text emphasis="bold">{title}</Text>
<Text appearance="subdued">
{variantTitle}
</Text>
</>
);
const order = (item) => (
<InlineLayout
columns={['auto', 'fill', 'auto']}
spacing="base"
blockAlignment="center"
>
{loading ? (
<SkeletonImage
blockSize={64}
inlineSize={64}
/>
) : (
<ProductThumbnail />
)}
<BlockStack spacing="extraTight">
{itemInfo(item)}
</BlockStack>
{loading ? (
<SkeletonText>{item.price}</SkeletonText>
) : (
<Text emphasis="bold">{item.price}</Text>
)}
</InlineLayout>
);
return (
<View maxInlineSize={400}>
<BlockStack>
{order(item1)}
{order(item2)}
</BlockStack>
</View>
);
};
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);
},
);

Was this page helpful?