Provide the values for the project as prompted by the yeoman generator. Below are the values which I provided for the example solution
- What is your solution name? (using-react-shimmer)
- Which baseline packages do you want to target for your component(s)? SharePoint Online only (latest)
- Where do you want to place the files? (Use arrow keys) Use the current folder
- Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites? (y/N) N
- Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant? (y/N) N
- Which type of client-side component to create? (Use arrow keys) WebPart
- What is your Web part name? (HelloWorld) CustomShimmer
- What is your Web part description? (Shimmer description)
- Which framework would you like to use? React
Step 3
Install PnPjs, for fetching the list of sites using Search
- npm install @pnp/pnpjs --save
Step 4
As we will be using Office UI React package, we can remove/uninstall the sp-office-ui-fabric-core package
- npm uninstall @microsoft/sp-office-ui-fabric-core --save
This step is optional. However, I would recommend uninstalling this package to reduce the bundle size of our SPFx components. We also need to change the import statements to use the styles from Fabric react package instead of @microsoft/sp-office-ui-fabric-core
Step 5
Open the src/webparts/customShimmer/CustomShimmerWebpart.ts and make the following changes.
-
- import {sp} from '@pnp/sp';
-
-
- export default class CustomShimmerWebPart extends BaseClientSideWebPart<ICustomShimmerWebPartProps> {
-
- public onInit(): Promise<void>{
- sp.setup({
- spfxContext: this.context
- });
- return Promise.resolve();
- }
-
- }
Step 6
Remove all the contents from src/webparts/customShimmer/components/CustomShimmer.module.scss file and replce with the following,
-
- @import '~office-ui-fabric-react/dist/sass/_References.scss';
-
- .customShimmer {
- .container {
- max-width: 700px;
- margin: 0px auto;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
- }
-
- .row {
- @include ms-Grid-row;
- @include ms-fontColor-white;
- background-color: $ms-color-themeDark;
- padding: 20px;
- }
-
- .column {
- @include ms-Grid-col;
- @include ms-lg10;
- @include ms-xl8;
- @include ms-xlPush2;
- @include ms-lgPush1;
- }
-
- .siteRow{
- @include ms-Grid-row;
- @include ms-fontColor-black;
- width: 350px;
- }
-
- .imgColumn{
- @include ms-Grid-col;
- @include ms-lg2;
- height: 40px;
- width: 40px;
- }
-
- .titleColumn{
- @include ms-Grid-col;
- @include ms-lg10;
- @include ms-font-l;
- line-height: 40px;
- height: 40px;
- }
-
- .subTitle {
- @include ms-font-l;
- @include ms-fontColor-white;
- }
- }
Step 7
Change the code in src/webparts/customShimmer/components/CustomShimmer.tsx, as shown below.
- import * as React from 'react';
- import styles from './CustomShimmer.module.scss';
- import { ICustomShimmerProps } from './ICustomShimmerProps';
- import { escape } from '@microsoft/sp-lodash-subset';
-
- import { Shimmer, ShimmerElementsGroup, ShimmerElementType } from 'office-ui-fabric-react/lib/Shimmer';
- import {sp, SearchQuery, SearchResults} from '@pnp/sp';
-
- export interface ICustomShimmerState{
- loaded: boolean;
- sites: any[];
- }
-
- export default class CustomShimmer extends React.Component<ICustomShimmerProps, ICustomShimmerState> {
- public constructor(props:ICustomShimmerProps, state:ICustomShimmerState){
- super(props);
- this.state = {
- loaded: false,
- sites:[
- {Title:"Site 1"},
- {Title:"Site 2"},
- {Title:"Site 3"},
- {Title:"Site 4"},
- {Title:"Site 5"},
- ]
- };
- }
-
- public render(): React.ReactElement<ICustomShimmerProps> {
- const elements = this.state.sites.map((val,index) => {
- return <div style={{padding:"10px", background:"white"}}>
- <Shimmer
- customElementsGroup={this._getElementsForSiteListing()}
- isDataLoaded={this.state.loaded}>
- <div className={ styles.siteRow }>
- <div className={ styles.imgColumn }>
- <img src={val.SiteLogo} height={40} width={40}/>
- </div>
- <div className={ styles.titleColumn }>
- {val.Title}
- </div>
- </div>
- </Shimmer>
- </div>;
- });
-
- return (<div className={ styles.customShimmer }>
- <div className={ styles.container }>
- <div className={ styles.row }>
- <div className={ styles.column }>
-
- {elements}
-
- </div>
- </div>
- </div>
- </div>);
- }
-
- private _getElementsForSiteListing= (): JSX.Element => {
- return (
- <div
- style={{ display: 'flex' }}
- >
- <ShimmerElementsGroup
- shimmerElements={[
- { type: ShimmerElementType.line, width: 40, height: 40 },
- { type: ShimmerElementType.gap, width: 10, height: 40 }
- ]}
- />
- <ShimmerElementsGroup
- flexWrap={true}
- shimmerElements={[
- { type: ShimmerElementType.gap, width: 370, height: 10 },
- { type: ShimmerElementType.line, width: 370, height: 10 },
- { type: ShimmerElementType.gap, width: 370, height: 10 }
- ]}
- />
- </div>
- );
- }
-
- public componentDidMount()
- {
-
-
- setTimeout(() => { sp.search({
- SelectProperties: ["Title","SiteLogo"],
- Querytext: `contentclass:STS_Site AND WebTemplate:'Group'`,
- RowLimit: 5
- }).then(w => {
- console.dir(w);
- this.setState({
- sites:w.PrimarySearchResults,
- loaded:true
- });
- });}, 5000);
-
- }
- }
We can use the isDataLoaded property of the Shimmer component to show the actual data when it is loaded.
Step 8
Save all the files, and run the solution to test on a SharePoint workbench,
This should now show a Shimmer effect, before loading the data.
Conclusion
Shimmers are the modern way of showing a loading or progress indicators and this article walks you through the steps to show a Fabric React Shimmer component within your SPFx solution.