JSFiddle - React, Tailwind, and code Playground

by neonDog

HTML

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.css">
<!-- 
  Bootstrap docs: https://getbootstrap.com/docs
-->

<div class="container text-center">
  
  <div class="row neon-resizer neon-resizable-item" data-position="bottom" data-type="padding">
    <div class="neon-resizable-col col" data-col="6">
      1 of
    </div>
    <div class="neon-resizable-col col" data-col="6">
      2 of 2
    </div>
  </div>
  
  <div class="row neon-resizable-item" data-position="bottom" data-type="padding">
    <div class="neon-resizable-col col" data-col="4">
      1 of 3
    </div>
    <div class="neon-resizable-col col" data-col="4">
      2 of 3
    </div>
    <div class="neon-resizable-col col" data-col="4">
      3 of 3
    </div>
  </div>
  
  <br>
  <br>
  <img class="neon-resizable-item border rounded" data-type="padding" src="https://image.shutterstock.com/image-photo/beautiful-water-drop-on-dandelion-260nw-789676552.jpg">
  
  
</div>

SCSS

.drag-bar {
  position: fixed;
  background: rgba(100, 100, 150, 0.3);
}

.row {
  background: #f8f9fa;
  min-height: 100px;
}


.neon-resizable-col {
    position: relative;
    border: 1px solid #aaa;

    &.active::after {
      background-color: var(--primary)!important;
    }

    &[data-col]::after {
      z-index:10;
      content: " ";
      background-color: #eee;
      position: absolute;
      right: -2px;
      width: 4px;
      height: 100%;
      cursor: w-resize;
      background-repeat: no-repeat;
      background-position: 50%;
      background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
    }
    
    &[data-position="bottom"]::before {
      z-Index:10;
      content: " ";
      position: absolute;
      bottom:-2px;
      height: 2px;
      width: 100%;
      cursor: s-resize;
      background-color: var(--primary);
    }
  
}

JavaScript

const applyColClass = function(el, cols, classPrefix) {
	const collClass = cols > 0 ? classPrefix + '-' + cols : classPrefix;
  el.className = collClass + ' neon-resizable-col';
  el.setAttribute('data-col', cols);
}


class NeonResizableColumn {

  constructor(settings = {}) {

    const defaults = {
      container: document.body,
      columns: 12,
      classPrefix: 'col-sm',
      mode: 'class', // 'class', 'percent', 'pixel'
    };

    this.options = Object.assign({}, defaults, settings);
		
    this.resetUI();
    
    this._animate = this._animate.bind(this);
    this._mousedown = this._mousedown.bind(this);
    this._mouseup = this._mouseup.bind(this);
    this._mousemove = this._mousemove.bind(this);
    this.moveListenersActive = false;
    this.eventListenersActive = false;
		
    this._eventListeners();
  }
  
  resetUI() {
  	this.ui = {mouse:[], dragBar:null, colSpans:[], panels:[], bounds:[], active:false, otherCols:0};
  }

  _mousedown(e) {
    if (this.ui.active) return;
		
    this.resetUI();
    const col = e.target.closest('.neon-resizable-col');
    if (!col) return;
    
    const b = col.getBoundingClientRect();
    
    const positions = ['top','right', 'bottom', 'left'];
    const intersects = [];
    for (let i=0; i < 3; i++) {
    	const pos = positions[i];
    	const axis = i & 1 ? 'clientX' : 'clientY';
      if (b[pos] - 3 < e[axis] && b[pos] + 3 > e[axis]) {
      	intersects.push(pos);
      }
      
    }
    
    if (intersects.length === 0) return;
    
    	e.preventDefault();
      e.stopPropagation();
      col.classList.add('active');
      
      const ui = this.ui;
      
      if (intersects.includes('right')) {
        ui.dragBar = document.createElement('div');
        ui.dragBar.className = 'drag-bar';
      	ui.dragBar.setAttribute('style', `width:${ 4 || b.width }px; height:${ b.height }px; top:${ b.top }px; left:${ b.right }px;`);
      	document.body.append(ui.dragBar);
      }
    
    ui.data = col.dataset;
  ...