React Two Column Layout With Adjustable Width Slider
- Zac Butko
- Sep 13, 2022
- 2 min read
What's the best way to build a modern React component that is able to seamlessly adjust the width of a two panel layout? This simple css task seems like it should be achievable using mouse events to control inline styles of our components. But getting it right with React components is a little tricky.
My solution was inspired by this answer on Stack Overflow which I appreciated since it had no external dependencies. Just plain old JavaScript. Some React libraries predictably exist to handle this functionality, the most popular as of writing is react-resize-panel with a very nice demo. However looking into the machinery of that package, it relies on an additional dependency "DragableCore" from react-dragable, part of react-grid-layout. For this exercise we don't need all that machinery. We're simply looking to have a main content area with two panels, and a divider which can adjust the width of the left panel to make the right bigger. This should just be a few lines of JavaScript and CSS with no external package dependencies.
Here is our main logic in App.js
import { useRef } from "react";
import "./styles.css";
const ResizableTwoPane = () => {
const left = useRef(null);
const right = useRef(null);
const div = useRef(null);
let md = null;
const onMouseMove = (e) => {
let dx = e.clientX - md.e.clientX;
left.current.style.width = md.leftWidth + dx + "px";
right.current.style.width = md.rightWidth - dx + "px";
};
const onMouseDown = (e) => {
md = {
e: e,
leftWidth: left.current.offsetWidth,
rightWidth: right.current.offsetWidth
};
document.onmousemove = onMouseMove;
document.onmouseup = () => {
document.onmousemove = document.onmouseup = md = null;
};
};
return (
<div className="colContainer">
<div className="col colLeft" ref={left} />
<div onMouseDown={onMouseDown} className="draggableDiv" ref={div}>
Drag me!
</div>
<div className="col colRight" ref={right} />
</div>
);
};And accompanying stylesheet
.colContainer {
display: flex;
width: 100%;
height: 10rem;
border: 1px solid black;
}
.col {
height: 100%;
display: flex;
box-sizing: border-box;
min-width: 3rem;
}
.colLeft {
width: 30%;
background-color: blue;
}
.colRight {
width: 70%;
background-color: teal;
}
.draggableDiv {
background: rgba(255, 255, 255, 0.522);
height: 100%;
box-sizing: border-box;
flex: 1 0 5rem;
padding: 0.5rem;
cursor: col-resize;
user-select: none;
position: relative;
}
The result:

Comments