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.

Name
Role
Department
Salary
Aria Chen
Engineering Lead
Engineering
$155,000
Marcus Webb
Product Manager
Product
$132,000
Priya Kapoor
Senior Designer
Design
$118,000
Jordan Ellis
Data Scientist
Analytics
$143,000
Sam Rivera
DevOps Engineer
Engineering
$128,000

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

PropTypeDefaultDescription
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.