Edit in GitHubLog an issue

Shimmer

The Shimmer component is a loading indicator that takes the shape of the component being loaded. Instead of blocking the entire page like a traditional full-screen loader, Shimmer loaders are component-shape specific to show users previews of what's loading on the page.

These previews improves the perceived performance of the app and prevents CLS (Content Layout Shift). The Shimmer component eliminates most of the CLS on a page, which helps improve Google Lighthouse scores.

Parameters

NameTypeDescription
classes
Object
Styles to apply to the root of the Shimmer. Available classes are root and root_[TYPE].
borderRadius
string | number
Border radius for the shimmer.
height
string | number
Sets the height of the Shimmer. Numbers are in rem units. Strings are used directly (Example: '100px').
width
string | number
Sets the width of the Shimmer. Numbers are in rem units. Strings are used directly (Example: '100px').
style
Object
CSS styles to apply to the Shimmer.
type
'rectangle' | 'button' | 'checkbox' | 'radio' | 'textArea' | 'textInput'
The base element shape to apply to the Shimmer.
children
node
Children to output within the Shimmer. Useful for setting image placeholders.

Properties

NameTypeDescription
classes
Object
is an object containing the class names for the Shimmer component.
classes.root
string
is the class for the container
classes.root_rectangle
string
is the class for the container of type rectangle
classes.root_button
string
is the class for the container of type button
classes.root_checkbox
string
is the class for the container of type checkbox
classes.root_radio
string
is the class for the container of type radio
classes.root_textArea
string
is the class for the container of type textArea
classes.root_textInput
string
is the class for the container of type textInput
borderRadius
number | string
is the border radius of the Shimmer
height
number | string
is the height of the Shimmer
width
number | string
is the width of the Shimmer
style
Object
is an object of inline styles
type
string
is the type of the Shimmer
children
node
are the children of the Shimmer

Source Code: pwa-studio/packages/venia-ui/lib/components/Shimmer/shimmer.js

Shimmer for Components

When loading data, previously we would return null (or a full-screen loader) instead of the actual component. We can now return a shimmer version of the component, which will take up the same space without relying on data.

Direct use of the Shimmer component within normal components should be avoided when possible. If the shimmer is replacing a component that is imported, a .shimmer.js file should be created for that imported component in its folder and exported in its index.js.

Example

There are 4 critical files for creating a Shimmer component:

  • Main.js - the main component that has the loading status and would usually return null for the component while loading
  • SubComponent/index.js - Previously would only export the main component. Must now export named variable for shimmer component
  • SubComponent/subComponent - Same SubComponent as usual
  • SubComponent/subComponent.shimmer.js - .shimmer.js extension is used for easily identifying that it's a shimmer and the component it's attached to. It can contain complex arrangement of base Shimmer elements, or include other subcomponents Shimmers.

Main.js

Copied to your clipboard
import React from 'react';
import SubComponent, { SubComponentShimmer } from '../path/to/SubComponent';
// ....
export default () => {
const { data, isLoading } = fetchData();
if (isLoading) {
return (
<SubComponentShimmer />
);
}
if (!data) {
return 'No data';
}
return (
<SubComponent someValue={data} />
);
};
// ....

../path/to/SubComponent/index.js

Copied to your clipboard
export { default } from './subComponent.js';
// Export named shimmer component
export { default as SubComponentShimmer } from './subComponent.shimmer.js';

../path/to/SubComponent/subComponent.js

Copied to your clipboard
import React from 'react';
import { shape, string } from 'prop-types';
import { useStyle } from '../../path/to/classify';
import defaultClasses from './subComponent.css';
const SubComponent = (props) => {
const classes = useStyle(defaultClasses, props.classes);
const { someValue } = props;
return (
<div className={classes.root}>
<div className={classes.item}>{someValue}</div>
</div>
);
};
SubComponent.defaultProps = {
classes: {}
};
SubComponent.propTypes = {
classes: shape({
root: string,
item: string
})
}
export default SubComponent;

../path/to/SubComponent/subComponent.shimmer.js

Copied to your clipboard
import React from 'react';
import { useStyle } from '../../path/to/classify';
import Shimmer from '../path/to/base/Shimmer';
import defaultClasses from './subComponent.css'; // Load same classes as real SubComponent
const SubComponentShimmer = (props) => {
// Important to still merge-in prop classes for extensibility/targetability
const classes = useStyle(defaultClasses, props.classes);
return (
<div className={classes.root}>
<Shimmer className={classes.item} />
</div>
);
};
SubComponentShimmer.defaultProps = {
classes: {}
};
SubComponentShimmer.propTypes = {
classes: shape({
root: string,
item: string
})
}
export default SubComponentShimmer;

Adjusting existing Shimmers

When you make layout changes to a Shimmer's parent component, you should also adjust the Shimmer component to match. In this example, we'll add a custom attribute shimmer to the detail section of the product page.

local-intercept.js

Copied to your clipboard
const { Targetables } = require('@magento/pwa-buildpack');
const targetables = Targetables.using(targets);
const productShimmerComponent = targetables.reactComponent(
'@magento/venia-ui/lib/RootComponents/Product/product.shimmer'
);
/**
* As a best practice, you should create a separate Shimmer file for the new attribute and import it into the
* productShimmerComponent. But for simplicity, we'll inline the jsx as shown here.
*/
productShimmerComponent.appendJSX(
'section className={classes.details}'
`<div className={classes.detailsTitle}>
<Shimmer width="100%" height={1} />
</div>
<Shimmer width="100%" height={1} />`
);

Accessibility

To maintain accessibility for screen readers, we can pass aria-live="polite" aria-busy="true" to the Shimmer component (or an element that wraps the Shimmer(s) in a more complex instance).

It's important to then add aria-live="polite" aria-busy="false" to the normal component that replaces the shimmer.

Example

Copied to your clipboard
// ....
import Shimmer from '../path/to/base/Shimmer';
// ....
export default () => {
// ....
return (
<Shimmer />
);
};
  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.