Skip to content

Column pinning

Pin a column and it stays in view while the rest of the grid scrolls sideways. The checkbox and the row-actions menu are the usual candidates: one at the start, one at the end.

Chloe Bosechloe.bose@mail.testActiveFreeSupportIntern$0.00165.6%Feb 21, 2023—Canada
Ishaan Garciaishaan.garcia@mail.testActiveProPlatformManager$36.00340.3%May 11, 2025—India
Ananya Iyerananya.iyer@corp.exampleActiveEnterprisePlatformLead$1,422.00188.3%May 26, 2024—Germany
Diya Sharmadiya.sharma@example.comActiveEnterpriseDesignDirector$3,950.005099.6%Jun 12, 2023—Canada
Noah Prabhakarannoah.prabhakaran@mail.testPausedFreeDataManager$0.00190.4%Dec 7, 2023Speaks at meetups.France
Elias Smithelias.smith@mail.testPausedProFinanceAnalyst$36.00311.2%Mar 31, 2026Wants SSO.India
Elias Kimelias.kim@mail.testActiveEnterpriseDesignPM$1,975.002517.4%Jun 18, 2026Asked about invoices.France
Kwame Duboiskwame.dubois@team.devInvitedFreeSupportIntern$0.00175.3%May 12, 2023Wants SSO.Australia
Freya Tanakafreya.tanaka@mail.testActiveFreeGrowthAnalyst$0.0019.4%Feb 10, 2023Needs onboarding call.Nigeria
Elias Müllerelias.muller@corp.examplePausedFreeSalesDesigner$0.00182.2%Nov 11, 2023—Canada
0 of 60 row(s) selected.
Page 1 of 6

Open a column’s menu (the ⋯ button at the right of its header, shown on hover and focus, or right-click the header) and choose Pin to start or Pin to end. A pinned header shows a pin icon, and so does its row in the View popover. Unpin sends it back.

To start pinned, set initialState.columnPinning:

<DataGrid
data={data}
columns={columns}
initialState={{ columnPinning: { start: ["name"], end: ["actions"] } }}
/>

If the grid has a checkbox column, pin it too (start: ["select", "name"]); otherwise the pinned name moves ahead of it.

From code, the TanStack API is one call away:

grid.table.getColumn("name")?.pin("start") // or "end", or false to unpin
grid.table.setColumnPinning({ start: ["name"], end: [] })
grid.table.resetColumnPinning()
  • Start and end, not left and right. TanStack Table v9 pins to logical regions. In a left-to-right layout start is the left edge; under dir="rtl" it is the right edge. The grid positions pinned cells with inset-inline-start and inset-inline-end, so a pinned column lands on the correct side in both directions with nothing extra from you.
  • Sticky, not split. The grid is one <table>. A pinned column’s header and cells get position: sticky with an offset equal to the widths of the pinned columns before it (column.getStart("start") on the start side, column.getAfter("end") on the end side). Nothing is cloned into a second table, so sorting, filtering, selection, keyboard navigation and editing work in a pinned column exactly as in any other. getPinningStyles(column, { header }) and pinningClasses(column) are exported if you render cells of your own.
  • Order. Start-pinned columns come first, in the order they were pinned; then the unpinned (“centre”) columns in their column order; then the end-pinned columns. Pinning appends the column to its region; unpinning returns it to its place in the centre order. Exports and the clipboard follow this on-screen order.
  • The edge. The last start-pinned column and the first end-pinned column draw a one-pixel, border-coloured inset shadow on their inner edge, and every pinned cell has an opaque background, so scrolling columns pass behind them rather than through them.
  • Pinned columns don’t drag. Drag-to-reorder works within the centre region. A pinned header has no drag handle and its menu hides Move left and Move right; unpin it to move it.
  • Resizing a pinned column shifts the offsets of the pinned columns after it. The footer row, when a column defines a footer, is pinned the same way.
  • Hiding a pinned column keeps it in the pinning state; show it again and it comes back pinned.
  • Group headers (col.group) pin all of their leaf columns together.
  • Persistence. columnPinning is part of the view the grid remembers with persist, and of every saved view. Reset view in the View popover clears it.

Column options (any column builder, or columnDef):

Option Type Default What it does
enablePinning boolean true false removes the pin items from this column’s menu (column.getCanPin() is false).

Grid options:

Option Type Default What it does
initialState.columnPinning ColumnPinningState empty Which columns start pinned, by id, in order. A persisted view wins over it.
table.enableColumnPinning boolean true Turns the feature off for every column (through the table escape hatch).
table.state.columnPinning ColumnPinningState Control the slice yourself, paired with table.onColumnPinningChange.

Helpers exported from the grid:

Export What it does
getPinningStyles(column, options?) The width, sticky position, inline inset and z-index for a cell of that column; pass { header: true } for a header cell.
pinningClasses(column) The opaque background and the edge shadow classes for a pinned cell.