<div id="content"></div>
//usual reset stuff
*,
*:before,
*:after,
ul,
li,
a,
button,
input,
h1,
h2,
h3,
h4,
h5,
h6,
p,
img,
image,
svg,
path,
g,
canvas {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
	background-color: transparent;
	border: none;
	text-decoration: none;
	font-family: 'Roboto';
	user-select: none;
	list-style: none;
	position: relative;
}

@mixin size($width:inherit, $height:inherit) {
	width: $width;
	height: $height;
}

@mixin flex($vertical, $horizontal, $direction:row) {
	display: flex;
	align-items: $vertical;
	justify-content: $horizontal;
	flex-direction: $direction;
}

@mixin border-radius($topLeft:50%, $topRight:50%, $botLeft:50%, $botRight:50%) {
  border-top-left-radius: $topLeft;
  border-top-right-radius: $topRight;
  border-bottom-left-radius: $botLeft;
  border-bottom-right-radius: $botRight;
}

$deepBlue-5: #f1f3f4;
$deepBlue-10: #e4e6ea;
$deepBlue-20: #CCCED5;
$deepBlue-40: #999EAC;
$deepBlue-60: #666D82;
$deepBlue-80: #333D59;
$deepBlue-90: #192445;
$deepBlue-100: #000C2F;
$deepBlue-120: #000923;

$blue: #2E90EB;
$salmon: #f56b72;

$swipes-shadow-one: 0 1px 3px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.12);
$swipes-shadow-two: 0 3px 6px rgba(0, 0, 0, 0.16),
0 3px 6px rgba(0, 0, 0, 0.23);
$swipes-shadow-three: 0 10px 20px rgba(0, 0, 0, 0.19),
0 6px 6px rgba(0, 0, 0, 0.23);
$swipes-shadow-four: 0 14px 28px rgba(0, 0, 0, 0.25),
0 10px 10px rgba(0, 0, 0, 0.22);
$swipes-shadow-five: 0 19px 38px rgba(0, 0, 0, 0.30),
0 15px 12px rgba(0, 0, 0, 0.22);

html,
body {
	@include size(100%);
  @include flex(center, center);
	min-height: 100vh;
	margin: 0;
	padding: 0;
	background-color: #FAFAFA;
	font-family: 'Roboto';
}

// Custome SCSS

.sw-loader__wrapper {
  position:relative;

  &--center {
    position:absolute;
    left: 50%;
    top:50%;
    transform: translate(-50%, -50%);
  }

  .sw-loader__holder {
    @include size(70%, 70%);
    margin-left: 15%; margin-top: 15%;
    position: relative;
    transform: rotate(-45deg);

    .rect {
      @include size(100%, 100%);
      position: absolute;
      left: 0; top: 0;
      background: linear-gradient(
        to right,
        #141562, 
        #486FBC, 
        #EAB5A1, 
        #8DD6FF, 
        #4973C9, 
        #D07CA7, 
        #F4915E, 
        #F5919E, 
        #B46F89, 
        #141562, 
        #486FBC);
      background-position: 0% 50%;
      background-size: 1000% 1000%;
      overflow: hidden;
      animation: moveGradient 15s infinite;
    }
  }
}

@keyframes moveGradient {
  to {
    background-position: 100% 50%;
  }
}
View Compiled
const { PropTypes } = React;
const TIMER = 150; // Milliseconds between moving the next block
const TRANSITION = .5 // Seconds to actually move one block
const DEF_SIZE = 60; // Pixels height/width
const GUTTER = 5; // Spacing in percentage between tiles
const initialState = {

  positions: {
    1: 'alpha',
    2: 'bravo',
    3: 'charlie',
    4: null,
    5: 'delta',
    6: 'echo',
    7: 'foxtrot'
  },
  stateNumber: 0
}

class Loader extends React.Component {
    constructor(props) {
    super(props)
    this.state = initialState;
    this.setNextState = this.setNextState.bind(this);
  }
  componentDidMount() {
    this.setTimer(TIMER);
  }
  setTimer(time){
    if(this.timer){
      clearInterval(this.timer);
    }
    this.timer = setInterval(this.setNextState, time);
  }
  componentWillUnmount(){
    clearInterval(this.timer);
  }
  clipPathForPosition(position){
    position = parseInt(position, 10);
    const SIZE = (100-2*GUTTER)/3;
    const VAR0 = '0% ';
    const VAR1 = (SIZE+GUTTER) + '% ';
    const VAR2 = (2*SIZE+2*GUTTER) + '% ';
    switch(position){
      case 1: return 'inset(' + VAR1 + VAR2 + VAR1 + VAR0 + ' round 5%)';
      case 2: return 'inset(' + VAR0 + VAR2 + VAR2 + VAR0 + ' round 5%)';
      case 3: return 'inset(' + VAR0 + VAR1 + VAR2 + VAR1 + ' round 5%)';
      case 4: return 'inset(' + VAR1 + VAR1 + VAR1 + VAR1 + ' round 5%)';
      case 5: return 'inset(' + VAR2 + VAR1 + VAR0 + VAR1 + ' round 5%)';
      case 6: return 'inset(' + VAR2 + VAR0 + VAR0 + VAR2 + ' round 5%)';
      case 7: return 'inset(' + VAR1 + VAR0 + VAR1 + VAR2 + ' round 5%)';
    }
  }
  tileIndexToMove(){
    switch(this.state.stateNumber){
      case 0: return 7;
      case 1: return 6;
      case 2: return 5;
      case 3: return 4;
      case 4: return 3;
      case 5: return 2;
      case 6: return 1;
      case 7: return 4;
    }
  }
  positionForTile(radioCommand){
    for(var position in this.state.positions){
      var tile = this.state.positions[position];
      if(tile === radioCommand){
        return position;
      }
    }
  }
  setNextState(){
    const currentPositions = this.state.positions;
    const emptyIndex = this.positionForTile(null);
    const indexToMove = this.tileIndexToMove();
    const newPositions = Object.assign({}, currentPositions, {
      [indexToMove]: null,
      [emptyIndex]: currentPositions[indexToMove]
    });

    const currentState = this.state.stateNumber;
    const nextState = (currentState === 7) ? 0 : currentState + 1;


    this.setState({stateNumber: nextState, positions: newPositions});
  }
  renderTiles(){
    return ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot'].map((radioCommand) => {
      const pos = this.positionForTile(radioCommand);
      const styles = {
        transition: (TRANSITION) + 's cubic-bezier(0.86, 0, 0.07, 1)',
        WebkitClipPath: this.clipPathForPosition(pos)
      }
      return <div key={"rect-" + radioCommand} style={styles} className={"rect " + radioCommand} />
    })
  }
  render() {

    const { size, style, center } = this.props;
    const styles = Object.assign({
      width: DEF_SIZE + 'px',
      height: DEF_SIZE + 'px'
    }, style);

    if ( size ) {
      styles.width = size + 'px';
      styles.height = size + 'px';
    }

    let className = "sw-loader__wrapper"
    if(center){
      className += " sw-loader__wrapper--center";
    }

    return (
      <div style={styles} className={className}>
        <div className="sw-loader__holder">
          {this.renderTiles()} 
        </div>
      </div>
    )
  }
}


class Container extends React.Component {
  render() {
    const data = {
      size: 200
    };

    return <Loader {...data} />
  }
}

ReactDOM.render(<Container />, document.getElementById('content'))
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://fb.me/react-15.1.0.min.js
  2. https://fb.me/react-dom-15.1.0.min.js