Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Resizable Columns Table Block for React

A translation workbench table whose column dividers are focusable separators: drag them or use the arrow keys (Shift for bigger steps, Home to reset), with minimum and maximum widths, truncated cells and a Reset widths button.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let people size a table's columns to what they are reading, with this resizable columns table for React with Base UI. A compact header holds a Reset widths Button, and under a hint line a hairline frame with a plus mark on each corner holds a scrolling region and a native table of eight strings from a shop app: the key, the English source, its French translation and a status Badge. On the end edge of the first three heads sits a divider, a focusable separator that exposes its value, minimum and maximum. Drag it, or focus it and press the arrow keys to move 8 pixels (32 with Shift); Home or a double click puts that column back, and the narrowest and widest a column goes are held. Long cells are cut with an ellipsis and carry their full text as a tooltip, the status column takes what is left, and a polite line says "Source 272 px". When the columns outgrow the frame the frame scrolls sideways on its own; the page never does, and the rows keep their height. It's built from Button, Badge and Guides, with a CSS entrance only. For translation tools, data grids and any table with text of very different lengths.

FAQ

How do I use my own columns?

Edit RESIZABLE (each resizable column's label, least width, widest and starting width, in pixels) and ENTRIES. The widths live in one array and reach the table as a CSS variable per head (--w), so a head's width is a class, never a number in a style object, and the table's own minimum width is their sum plus the status column's least. The last column is not resizable on purpose: it takes whatever room is left, so the table always fills its frame.

How do I resize with the keyboard?

Tab to a divider ("Resize the Source column"); the arrow that points toward the end of the line widens it and the opposite one narrows it, 8 pixels at a time, 32 with Shift, and Home puts the column back at its starting width. The separator's value, minimum and maximum are exposed (aria-valuenow, aria-valuemin, aria-valuemax), and after each press the polite line says the new width, or that the column is at its minimum or maximum. In a right-to-left page the arrows swap sides with the layout.

How does dragging work, and what about touch?

Pressing a divider captures the pointer, and as it moves the column takes the width it started with plus the distance travelled, held between the column's limits; letting go announces the final width. The divider is 24 pixels wide, so it is an easy target for a finger, and it has touch-none so the page doesn't scroll while you drag. A double click on a divider puts that column back.

What happens on a phone?

The table keeps its widths and the framed region scrolls sideways under your finger, with the hint line above it. The page itself never scrolls sideways. The dividers stay 24 pixels wide, and every column can still be sized with a drag.

What happens to text that no longer fits?

Source and translation cells are cut with an ellipsis and keep their full text as a title, so a hover shows it; the full text is still there for a screen reader. The table uses a fixed layout so a width means what it says, and rows stay one line tall whatever the widths, so resizing never changes the block's height.

What stays local, and how do I remember the widths?

The widths live in one useState array; nothing is saved or sent. To keep them, store the array with the user's settings and pass it as the initial state. Reset widths returns to STARTS, the starting widths written in RESIZABLE.

  • Pro

    Column Reorder Table

    Columns and paging

    A pipeline table with a Column order list beside it: Move earlier and Move later buttons reorder the columns and announce the move, a grip drags as an extra, and Reset restores the default order.

  • Pro

    Column Visibility Table

    Columns and paging

    A shipment table with a Columns popover of checkboxes: tick a column to show or drop it, one always stays on, a badge counts what is hidden, and Reset restores the default six of eight.

  • Pro

    Pinned Columns Table

    Columns and paging

    A vehicle log of ten columns whose first and last stay pinned while the rest scroll under them, with a shadow that appears only when there is something to scroll under and a switch that turns the pins off.

  • Pro

    Density Table

    Columns and paging

    A page list with a three-way density toggle (Compact, Comfortable, Spacious) that sets row height and text size together, in a fixed-height region so the block never changes height, with a line that says what the mode does.

  • Pro

    Sticky Header Table

    Columns and paging

    A sixty-row cash ledger in a fixed-height region where the column heads and the day row stay at the top while you scroll, with a Jump to menu of weeks that scrolls the region and a band that names the day at the top.

  • Pro

    Sortable Members Table

    Sort and search

    A members table whose column heads are buttons: press one to sort, again to reverse, a third time for the original order, with aria-sort on the active head, ties settled by name and a spoken line for each result.