Resizeable Demo

by Nicholas Berlette

HTML

<div id="resizeable">
  <div id="handle"></div>
</div>

CSS

.resizeable {
  --resizeable-width: 300px;
  --resizable-height: 100vh;
  
  width: var(--resizeable-width);
  min-width: var(--min-width, 1vw);
  max-width: var(--max-width, 100vw);
  height: var(--resizable-height);
  min-height: var(--min-height, 1vh);
  max-height: var(--max-height, 100vh);
  background-color: grey;
}

.x-handle {
  float: right;
  height: 100vh;
  width: 1px;
  background-color: #0006;
  border-left: 1px solid #fff6;
  border-right: 1px solid #fff6;
  z-index: 1;
}

.x-handle::after {
  content: "";
  width: 9px;
  position: absolute;
  top: 0;
  bottom: 0;
  margin-left: -4px;
  background-color: transparent;
  cursor: ew-resize;
  z-index: 2;
}

.y-handle {
  width: 100vw;
  height: 1px;
  background-color: #0006;
  border-top: 1px solid #fff6;
  border-bottom: 1px solid #fff6;
  z-index: 1;
}

.y-handle::after {
  content: "";
  height: 9px;
  position: absolute;
  top: 0;
  bottom: 0;
  margin-top: -4px;
  background-color: transparent;
  cursor: ns-resize;
  z-index: 2;
}



body {
  margin: 0px;
}

* {
  box-sizing: border-box;
}

JavaScript

const getResizeableElement = () => $(".resizeable");
const getHandleElement = (dir = "x") => $(`.${dir}-handle`);
const minPaneWidth = 150;
const maxPaneWidth = document.body.clientWidth * 0.75;
const minPaneHeight = 150;
const maxPaneHeight = document.body.clientHeight * 0.75;

getResizeableElement().style.setProperty('--max-width', `${maxPaneWidth}px`);
getResizeableElement().style.setProperty('--min-width', `${minPaneWidth}px`);
getResizeableElement().style.setProperty('--max-height', `${maxPaneHeight}px`);
getResizeableElement().style.setProperty('--min-height', `${minPaneHeight}px`);


const setPaneWidth = (width) => {
  getResizeableElement().style
    .setProperty('--resizeable-width', `${width}px`);
};

const getPaneWidth = () => {
  const computed = getComputedStyle(getResizeableElement());
  return parseInt(computed.getPropertyValue('--resizeable-width'), 10);
};

const setPaneHeight = (width) => {
  getResizeableElement().style.setProperty('--resizeable-width', `${width}px`);
};

const getPaneWidth = () => {
  const computed = getComputedStyle(getResizeableElement());
  return parseInt(computed.getPropertyValue('--resizeable-width'), 10);
};

const startDragging = (event) => {
  event.preventDefault();
  const host = getResizeableElement();
  const startingPaneWidth = getPaneWidth();
  const xOffset = event.pageX;

  const mouseDragHandler = (moveEvent) => {
    moveEvent.preventDefault();
    const primaryButtonPressed = moveEvent.buttons === 1;
    if (!primaryButtonPressed) {
      setPaneWidth(Math.min(Math.max(getPaneWidth(), minPaneSize), maxPaneSize));
      document.body.removeEventListener('pointermove', mouseDragHandler);
      return;
    }

    const paneOriginAdjustment = 'left' === 'right' ? 1 : -1;
    setPaneWidth((xOffset - moveEvent.pageX ) * paneOriginAdjustment + startingPaneWidth);
  };
  const remove = document.body.addEventListener('pointermove', mouseDragHandler);
};

getHandleElement().addEventListener('mousedown', startDragging);