Skip to content

Instantly share code, notes, and snippets.

@corysimmons
Created January 8, 2024 10:05
Show Gist options
  • Save corysimmons/d85d6a6edadab1f0405b16640d2e8827 to your computer and use it in GitHub Desktop.
Save corysimmons/d85d6a6edadab1f0405b16640d2e8827 to your computer and use it in GitHub Desktop.
Horizontally draggable React component
import React, { useRef, useState } from "react";
interface DraggableScrollContainerProps {
children: React.ReactNode;
className?: string
}
const DraggableScrollContainer: React.FC<DraggableScrollContainerProps> = ({
children,
className,
}) => {
const [isDragging, setIsDragging] = useState(false);
const [startX, setStartX] = useState(0);
const ref = useRef<HTMLDivElement>(null);
const onDragStart = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
setIsDragging(true);
setStartX(e.pageX - (ref.current?.offsetLeft ?? 0));
if (ref.current) {
ref.current.style.cursor = "grabbing";
ref.current.style.userSelect = "none";
}
};
const onDragEnd = () => {
setIsDragging(false);
if (ref.current) {
ref.current.style.cursor = "grab";
ref.current.style.removeProperty("user-select");
}
};
const onDrag = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (!isDragging || !ref.current) return;
const x = e.pageX - ref.current.offsetLeft;
const walk = x - startX;
ref.current.scrollLeft = ref.current.scrollLeft - walk;
setStartX(x);
};
return (
<div
ref={ref}
onMouseDown={onDragStart}
onMouseLeave={onDragEnd}
onMouseUp={onDragEnd}
onMouseMove={onDrag}
style={{
display: "flex",
overflowX: "auto",
cursor: "grab",
whiteSpace: "nowrap",
}}
className={className}
>
{children}
</div>
);
};
export default DraggableScrollContainer;
// Usage
<div style={{ width: "calc(100vw - 200px)" }}> // Fixed width container
<DraggableScrollContainer className="styled-scrollbars"> // Style those huge/ugly scrollbars to be aesthetic
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
</DraggableScrollContainer>
</div>
/* This makes the scrollbars look nice */
.styled-scrollbars {
scrollbar-color: rgba(255, 255, 255, 0.1) rgba(255, 255, 255, 0.05);
}
.styled-scrollbars::-webkit-scrollbar {
height: 3px;
}
.styled-scrollbars::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
}
.styled-scrollbars::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment