<div id="viewDiv"></div>
<div id="slider">
  <div id="btnExpand" class="light-blue"></div>
  <div id="slider-content">
    <div id="legendDiv"></div>
  </div>
</div>
html,
body,
#viewDiv {
  font-family: Helvetica, Arial, Sans-Serif;
  overflow: hidden;
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
}

#slider {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  padding: 0;
  margin: 0;
  width: 300px;
  margin-left: -280px;
}

#slider-content {
  position: absolute;
  left: 0;
  top: 0;
  right: 20px;
  bottom: 0;
  padding: 0;
  margin: 0;
  background-color: #fff;
  opacity: 1;
}

#legendDiv {
  font-size: 1.2em;
  padding: 20px;
}

#btnExpand {
  width: 20px;
  height: 100%;
  float: right;
  background-color: #e8912e;
}
require([
  "esri/WebMap",
  "esri/views/MapView",
  "esri/widgets/Legend"
], function(WebMap, MapView, Legend) {


  const btnExpand = document.getElementById("btnExpand");
  const slider = document.getElementById("slider");
  const legendDiv = document.getElementById("legendDiv");
  const defaultPadding = 20;

  const map = new WebMap({
    portalItem: {
      id: "2460fa4e72044a33a465a8ffd9bdf774"
    }
  })

  const view = new MapView({
    container: "viewDiv",
    map: map,
    padding: {
      left: defaultPadding
    }
  });

  view.when(() => {
    const legend = new Legend({
      container: legendDiv,
      view: view
    });
  });

  const margin = -280;
  const increment = 1;

  // http://codereview.stackexchange.com/questions/106946/simple-animation-method-with-requestanimationframe-code-structure
  function animate(options) {
    options = options || {};

    // defaults
    const duration = options.duration || 500,
          ease = options.easing || (a => a),
          onProgress = options.onProgress || (_ => _),
          onComplete = options.onComplete || (_ => _),
          from = options.from || {},
          to = options.to || {};

    // runtime variables
    const startTime = Date.now();

    function update() {
      let deltaTime = Date.now() - startTime,
            progress = Math.min(deltaTime / duration, 1),
            factor = ease(progress),
            values = {},
            property;

      for(property in from) {
        if(from.hasOwnProperty(property) && to.hasOwnProperty(property)) {
          values[property] = from[property] + (to[property] - from[property]) * factor;
        }
      }

      onProgress(values);

      if(progress === 1) {
        onComplete(deltaTime);
      } else {
        requestAnimationFrame(update);
      }
    }

    requestAnimationFrame(update);
  }

  const inSine = (t) => (
    -Math.cos(t * Math.PI / 2) + 1
  );

  const updatePadding = (value) => (
    { left: value - margin + defaultPadding }
  );

  function expand() {
    animate({
      easing: inSine,
      onProgress({a}) {
        slider.style.marginLeft = `${a}px`;
        // update view padding
        view.padding = updatePadding(a);
      },
      onComplete() {
        btnExpand.removeEventListener("click", expand);
        btnExpand.addEventListener("click", collapse);
      },
      from: { a: margin },
      to: { a: 0 }
    });
  }

  function collapse() {
    animate({
      easing: inSine,
      onProgress({a}) {
        slider.style.marginLeft = `${a}px`;
        // update view padding
        view.padding = updatePadding(a);
      },
      onComplete() {
        btnExpand.removeEventListener("click", collapse);
        btnExpand.addEventListener("click", expand);
      },
      from: { a: 0 },
      to: { a: margin }
    });
  }

  btnExpand.addEventListener("click", expand);
});

External CSS

  1. https://js.arcgis.com/4.12/esri/css/main.css

External JavaScript

  1. https://js.arcgis.com/4.12