Add drag-to-scroll feature to your UI
3 min read
•
Jan 9, 2026
Hi, welcome to my blog, this is Alan!
Today, I’m gonna share with you how to add drag-to-scroll to you ui. This allows users to drag to scroll instead of using just scrollbar, very convenient.
Press enter or click to view image in full size

Result
In this example, I use a table but it can be applied with any content that is scrollable
1import React, { useRef } from 'react'2import {3 Table,4 TableBody,5 TableCell,6 TableContainer,7 TableHead,8 TableRow,9 Paper,10} from '@mui/material'11import { faker } from '@faker-js/faker'1213const columns = [14 { id: 'firstName', label: 'First Name' },15 { id: 'lastName', label: 'Last Name' },16 { id: 'age', label: 'Age' },17 { id: 'street', label: 'Street' },18 { id: 'address', label: 'Address' },19 { id: 'state', label: 'State' },20 { id: 'country', label: 'Country' },21 { id: 'zipcode', label: 'Zipcode' },22]23interface RowData {24 firstName: string25 lastName: string26 age: number27 street: string28 address: string29 state: string30 country: string31 zipcode: string32}3334const createData = (): RowData[] => {35 return Array.from({ length: 10 }, () => ({36 firstName: faker.person.firstName(),37 lastName: faker.person.lastName(),38 age: faker.number.int({ min: 18, max: 80 }),39 street: faker.location.street(),40 address: faker.location.streetAddress(),41 state: faker.location.state(),42 country: faker.location.country(),43 zipcode: faker.location.zipCode(),44 }))45}4647const Home = () => {48 const [rows, setRows] = React.useState<RowData[]>([])49 const refTable = useRef<HTMLDivElement>(null)5051 React.useEffect(() => {52 setRows(createData())53 }, [])5455 return (56 <TableContainer57 ref={refTable}58 component={Paper}59 sx={{ maxWidth: '50vw', mx: 'auto' }}60 >61 <Table sx={{ tableLayout: 'fixed' }}>62 <TableHead>63 <TableRow>64 {columns.map((column) => (65 <TableCell key={column.id} sx={{ width: 300 }}>66 {column.label}67 </TableCell>68 ))}69 </TableRow>70 </TableHead>71 <TableBody>72 {rows.map((row, index) => (73 <TableRow key={index}>74 {columns.map((column) => (75 <TableCell key={column.id} sx={{ width: 300 }}>76 {row[column.id as keyof RowData]}77 </TableCell>78 ))}79 </TableRow>80 ))}81 </TableBody>82 </Table>83 </TableContainer>84 )85}8687export default Home
First, we need to define some mouse events to capture the move and calculate distance of the move of the cursor.
1 useEffect(() => {2 let isMounseDown = false3 const startPosition = { x: 0, y: 0 }45 const mousedown = (event: MouseEvent) => {6 startPosition.x = event.clientX7 startPosition.y = event.clientY89 isMounseDown = true10 refTable.current!.style.cursor = 'grabbing'11 }12 const mouseup = (event: MouseEvent) => {13 isMounseDown = false14 startPosition.x = 015 startPosition.y = 016 refTable.current!.style.cursor = ''17 }18 const mousemove = (event: MouseEvent) => {19 if (isMounseDown) {20 const x = event.pageX - refTable.current!.offsetLeft21 const deltaX = event.clientX - startPosition.x22 }23 }2425 document.addEventListener('mousedown', mousedown)26 document.addEventListener('mouseup', mouseup)27 document.addEventListener('mousemove', mousemove)2829 return () => {30 document.removeEventListener('mousedown', mousedown)31 document.removeEventListener('mouseup', mouseup)32 document.removeEventListener('mousemove', mousemove)33 }34 }, [])
Next, we use the moving distance of the cursor to set scroll value of the table container.
Keep the original position of scroll of table container before dragging, then we add up moving distance of cursor to the original scroll position.
Press enter or click to view image in full size

Great! But it should limit the dragging inside the area of table only, right? not everywhere like that.
Let’s add a check to it work as expected
Add a variable to keep the element when mouse down, then when dragging, we check if table container contains that element. If it doesn’t, we ignore.
Add mousedownElement and isCursorAtTable as below:
Press enter or click to view image in full size

It should work as we expected now.
Try this on other scrollable are, not only table, bring a better UI to your clients.
Example source code: https://github.com/alanng2050/blog-demo/tree/main/drag-to-scroll
Good luck with your project!
Thanks for reading.