Skip to content

Conversation

@npokc123
Copy link
Contributor

@npokc123 npokc123 commented Feb 9, 2026

Motivation

I'm a big fan of Mantine DataTable and use it extensively in my projects. I needed the ability to pin more than just the first/last column, and I believe many users would benefit from this as well. This PR extends the pinning system to support arbitrary columns pinned to either side, with an optional interactive UI for end users.

New API

Static pinning — pinned prop on column

columns={[
  { accessor: 'id', pinned: 'left' },
  { accessor: 'firstName', pinned: 'left' },
  { accessor: 'actions', pinned: 'right' },
  // ... unpinned columns scroll freely between the pinned zones
]}

Interactive pinning — pinnable prop on column

  columns={[
    { accessor: 'firstName', pinnable: true },
    { accessor: 'lastName', pinnable: true, pinned: 'left' }, // initial state
  ]}

When pinnable: true, a pin icon appears in the column header on hover. Clicking it opens a small popover where the user can choose to pin the column left, right, or unpin it. Pinning state is persisted to localStorage when storeColumnsKey is provided (works alongside existing column toggling/reordering/resizing).

What's inside

New files

  • useDataTablePinnedColumns hook — measures column widths from the DOM, computes cumulative offsets, handles RTL and tracking changes
  • useDataTableColumnPinning hook — manages interactive pinning state with localStorage persistence
  • DataTablePinnableDropdown component — hover popover with pin left/right/unpin actions
  • 3 SVG icons (IconPin, IconArrowLeft, IconArrowRight)
  • Example page pinning-arbitrary-columns with 5 demos

Architecture

  • Inline styles for position: sticky + computed offsets
  • Data attributes (data-pinned, data-pinned-shadow) for CSS shadows and overlays
  • DOM as source of truth — widths are measured from actual rendered elements, so visibleMediaQuery (columns returning null) is handled correctly
  • Old CSS selectors (:first-of-type / :last-of-type with ~170 lines of rules including RTL mixins) replaced with ~30 lines of attribute-based CSS

Backward compatibility

  • pinFirstColumn / pinLastColumn props continue to work — they are resolved internally by the hook based on the actual first/last visible
    column in the DOM
  • No breaking changes to the existing API

Integration with existing features

  • Column groups — group header is pinned when all its visible leaf columns are pinned to the same side (see example)
  • Selection column — offset of the first left-pinned data column accounts for the selection column width
  • Column dragging (DnD) — drag between pinning zones is blocked (left ↔ unpinned ↔ right); reordering within a zone works as before
  • Resizable columns — per-cell ResizeObserver recalculates offsets in real time during column resize
  • Column toggling — pinnable works alongside toggleable; pinning state persists independently
  • RTL — single swap layer in JS (logical left → physical right); CSS shadows use physical side with no RTL mixins, avoiding double-flip issues
  • noHeader — hook falls back to measuring first row

Sorry for the wall of text — it's a big change so I tried to explain everything clearly.
Would love to hear your thoughts. Happy to make any changes needed.

@codesandbox
Copy link

codesandbox bot commented Feb 9, 2026

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@npokc123 npokc123 closed this Feb 9, 2026
@npokc123 npokc123 reopened this Feb 9, 2026
@npokc123 npokc123 changed the title Full pinning Arbitrary column pinning Feb 9, 2026
@npokc123
Copy link
Contributor Author

npokc123 commented Feb 9, 2026

@icflorescu I got a bit confused with the branches - did I open the PR into the correct branch, or does something need to be changed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants