+ { !contentLoaded && (
+
+ { customElementsGroup ? customElementsGroup : }
+
+ ) }
+ { children &&
{ children }
}
+ { ariaLabel &&
+ !isDataLoaded && (
+
+ ) }
+
+ );
+ }
+}
diff --git a/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.checklist.ts b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.checklist.ts
new file mode 100644
index 00000000000000..e738f413c7fb97
--- /dev/null
+++ b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.checklist.ts
@@ -0,0 +1,9 @@
+import { ChecklistStatus } from '../../demo/ComponentStatus/ComponentStatus.types';
+
+export const ShimmerStatus = {
+ keyboardAccessibilitySupport: ChecklistStatus.notApplicable,
+ markupSupport: ChecklistStatus.unknown,
+ highContrastSupport: ChecklistStatus.pass,
+ rtlSupport: ChecklistStatus.pass,
+ testCoverage: ChecklistStatus.unknown
+};
diff --git a/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.styles.ts b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.styles.ts
new file mode 100644
index 00000000000000..193f3f3a1e3c0f
--- /dev/null
+++ b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.styles.ts
@@ -0,0 +1,108 @@
+import { IShimmerStyleProps, IShimmerStyles } from './Shimmer.types';
+import { keyframes, getGlobalClassNames, hiddenContentStyle, HighContrastSelector } from '../../Styling';
+import { getRTL } from '../../Utilities';
+
+const GlobalClassNames = {
+ root: 'ms-Shimmer-container',
+ shimmerWrapper: 'ms-Shimmer-shimmerWrapper',
+ dataWrapper: 'ms-Shimmer-dataWrapper'
+};
+
+const BACKGROUND_OFF_SCREEN_POSITION = '1000%';
+
+const shimmerAnimation: string = keyframes({
+ '0%': {
+ backgroundPosition: `-${BACKGROUND_OFF_SCREEN_POSITION}`
+ },
+ '100%': {
+ backgroundPosition: BACKGROUND_OFF_SCREEN_POSITION
+ }
+});
+
+const shimmerAnimationRTL: string = keyframes({
+ '100%': {
+ backgroundPosition: `-${BACKGROUND_OFF_SCREEN_POSITION}`
+ },
+ '0%': {
+ backgroundPosition: BACKGROUND_OFF_SCREEN_POSITION
+ }
+});
+
+export function getStyles(props: IShimmerStyleProps): IShimmerStyles {
+ const { isDataLoaded, className, theme, transitionAnimationInterval } = props;
+
+ const { palette } = theme;
+ const classNames = getGlobalClassNames(GlobalClassNames, theme);
+
+ const isRTL = getRTL();
+
+ return {
+ root: [
+ classNames.root,
+ {
+ position: 'relative',
+ height: 'auto'
+ },
+ className
+ ],
+ shimmerWrapper: [
+ classNames.shimmerWrapper,
+ {
+ background: `${palette.neutralLighter}
+ linear-gradient(
+ to right,
+ ${palette.neutralLighter} 0%,
+ ${palette.neutralLight} 50%,
+ ${palette.neutralLighter} 100%)
+ 0 0 / 90% 100%
+ no-repeat`,
+ animationDuration: '2s',
+ animationTimingFunction: 'ease-in-out',
+ animationDirection: 'normal',
+ animationIterationCount: 'infinite',
+ animationName: isRTL ? shimmerAnimationRTL : shimmerAnimation,
+ transition: `opacity ${transitionAnimationInterval}ms`,
+ selectors: {
+ [HighContrastSelector]: {
+ background: `WindowText
+ linear-gradient(
+ to right,
+ transparent 0%,
+ Window 50%,
+ transparent 100%)
+ 0 0 / 90% 100%
+ no-repeat`
+ }
+ }
+ },
+ isDataLoaded && {
+ opacity: '0',
+ position: 'absolute',
+ top: '0',
+ bottom: '0',
+ left: '0',
+ right: '0'
+ }
+ ],
+ dataWrapper: [
+ classNames.dataWrapper,
+ {
+ position: 'absolute',
+ top: '0',
+ bottom: '0',
+ left: '0',
+ right: '0',
+ opacity: '0',
+ background: 'none',
+ backgroundColor: 'transparent',
+ border: 'none',
+ transition: `opacity ${transitionAnimationInterval}ms`
+ },
+ isDataLoaded && {
+ opacity: '1',
+ position: 'static'
+ }
+ ],
+ screenReaderText: hiddenContentStyle
+ };
+}
diff --git a/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.test.tsx b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.test.tsx
new file mode 100644
index 00000000000000..140cec839e3b56
--- /dev/null
+++ b/packages/office-ui-fabric-react/src/components/Shimmer/Shimmer.test.tsx
@@ -0,0 +1,91 @@
+import * as React from 'react';
+import * as renderer from 'react-test-renderer';
+import { mount } from 'enzyme';
+
+import { Shimmer } from './Shimmer';
+import { ShimmerElementType as ElemType, IShimmer } from './Shimmer.types';
+import { ShimmerElementsGroup } from './ShimmerElementsGroup/ShimmerElementsGroup';
+
+describe('Shimmer', () => {
+ it('renders Shimmer correctly', () => {
+ const component = renderer.create(
+