Resizable columns
Enable drag-to-resize handles on column headers by setting resizable.
Users drag the right edge of any header cell to adjust its width. Resize is fully
compatible with sorting, pagination, filtering, pinning, and column reordering.
Resizable columns
Drag the right edge of any column header to resize it.
Drag the right edge of any column header to resize it.
import DataTable, { type TableColumn } from 'react-data-table-component';
const columns: TableColumn<Employee>[] = [
{ name: 'Name', selector: r => r.name, width: '180px', minWidth: '100px' },
{ name: 'Role', selector: r => r.role, minWidth: '120px' },
{ name: 'Department', selector: r => r.department, width: '140px', minWidth: '80px' },
{ name: 'Salary', selector: r => r.salary, width: '110px', right: true,
format: r => `$${r.salary.toLocaleString()}` },
];
<DataTable columns={columns} data={data} resizable highlightOnHover /> How it works
The resize handle sits straddling the right edge of each header cell, a 6 px hit area
centered on the column boundary so it aligns with the column separator. On
mousedown, a global mousemove listener tracks the delta and
writes the new width to component state; the affected column receives an inline
width style. Only the resized column re-renders.
Initial and minimum widths
width sets the starting width; minWidth clamps how small a
user can drag the column. Columns without a fixed width start at their
natural flex width and remain resizable.
const columns: TableColumn<Employee>[] = [
{ name: 'Name', selector: r => r.name, width: '200px', minWidth: '120px' },
{ name: 'Status', selector: r => r.status, width: '100px' },
{ name: 'Notes', selector: r => r.notes, /* grows to fill remaining space */ },
];
<DataTable columns={columns} data={data} resizable /> The hard floor is 40 px. DataTable won't allow narrower than that regardless of minWidth.
Visual indicator
The handle is invisible until hover. On hover or active drag, a 2 px center line
appears in your primary color (--rdt-color-primary). The line sits exactly
on the column boundary so it visually replaces the separator while resizing.
Persisting widths
Column widths live in component state only. They reset on remount. DataTable doesn't expose a single "widths changed" callback because the resize handler doesn't propagate to props. The reliable way to persist is to observe the DOM:
import { useEffect, useRef, useState } from 'react';
import DataTable, { type TableColumn } from 'react-data-table-component';
const STORAGE_KEY = 'employees-table-widths';
function loadWidths(): Record<string, string> {
try { return JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '{}'); }
catch { return {}; }
}
export default function App() {
const wrapperRef = useRef<HTMLDivElement>(null);
const [saved] = useState(loadWidths);
useEffect(() => {
const el = wrapperRef.current;
if (!el) return;
let timer: ReturnType<typeof setTimeout>;
const observer = new MutationObserver(() => {
clearTimeout(timer);
timer = setTimeout(() => {
const widths: Record<string, string> = {};
el.querySelectorAll<HTMLElement>('.rdt_TableCol').forEach(col => {
const id = col.dataset.columnId;
if (id && col.style.width) widths[id] = col.style.width;
});
localStorage.setItem(STORAGE_KEY, JSON.stringify(widths));
}, 200);
});
observer.observe(el, { attributes: true, attributeFilter: ['style'], subtree: true });
return () => observer.disconnect();
}, []);
const columns: TableColumn<Employee>[] = [
{ id: 'name', name: 'Name', selector: r => r.name,
width: saved['name'] ?? '180px' },
{ id: 'salary', name: 'Salary', selector: r => r.salary, right: true,
width: saved['salary'] ?? '110px' },
];
return (
<div ref={wrapperRef}>
<DataTable columns={columns} data={data} resizable />
</div>
);
} See recipes for the same pattern with debouncing.
With column pinning
Resize works on pinned columns. When a pinned column's width changes, the sticky offsets for columns pinned further from the edge update automatically. The pin band shifts to stay aligned.
Resetting widths
Force a remount of DataTable to clear all resize state. The simplest approach is a
React key bump:
const [resetKey, setResetKey] = useState(0);
<button onClick={() => {
localStorage.removeItem(STORAGE_KEY);
setResetKey(k => k + 1);
}}>Reset column widths</button>
<DataTable key={resetKey} columns={columns} data={data} resizable /> Accessibility
The resize handle is mouse-only. Keyboard users cannot drag-resize. If keyboard-accessible resizing matters for your audience, provide a settings UI (a popover with width inputs per column) as an alternative.
Prop reference
| Prop | Type | Default | Description |
|---|---|---|---|
resizable | boolean | false | Show resize handles on column header right edges. |
column.width | string | - | Initial width (e.g. "180px"). |
column.minWidth | string | "100px" | Minimum width the user can resize to. Hard floor of 40 px applies regardless. |