Wide tables with 20+ columns become unusable without pinning. Users lose context as they scroll horizontally—what row am I on? Pin the identifier column on the left and an actions column on the right and the UX clicks back into place.
This tutorial walks through column pinning patterns for Vue 3 data grids and shows the Simple Table for Vue setup with the Composition API.
If you also need virtualization, grouping with aggregations, and inline editing alongside pinning, Simple Table for Vue is the focused MIT pick.
Why it matters
Context anchoring
Users don't lose track of what row they're on as they scroll horizontally.
Action accessibility
Pin Edit / Delete / Open buttons on the right so they're always within reach.
Wide-table support
30+ columns become navigable when key columns stay sticky.
Excel-like ergonomics
Power users expect Freeze Panes; pinning delivers the same affordance.
Vue library comparison
| Library | Support | Notes |
|---|---|---|
| Simple Table for Vue | Built-in (left + right) | pinned: 'left' | 'right' on HeaderObject; sticky on horizontal scroll. |
| PrimeVue DataTable | Built-in | frozen prop on <Column>; alignFrozen='left'|'right'. |
| Element Plus el-table | Built-in | <el-table-column fixed="left" /> or fixed="right". |
| Vuetify v-data-table | Manual | No native sticky columns; use position: sticky CSS yourself. |
| Naive UI n-data-table | Built-in | fixed: 'left' | 'right' on column defs. |
Implementation: Simple Table for Vue
Set pinned: 'left' or pinned: 'right' on individual HeaderObjects. Simple Table handles z-index, sticky positioning, and shadow indicators automatically.
columnResizing if users should be able to resize pinned columns.Common pitfalls
Too many pinned columns
Problem: Users pin 8 of 12 columns; the scrolling area becomes useless.
Solution: Cap pinned columns at 2-3 each side, or warn the user beyond a threshold.
Pinned column width mismatch
Problem: Resizing a pinned column doesn't update the sticky offset.
Solution: Pick a library that handles offset recalculation on resize. Simple Table does this automatically.
Z-index battles with editors / dropdowns
Problem: Cell editors render below the pinned column, getting clipped.
Solution: Render editors / popovers in a portal at the document root (use <Teleport to="body">).
Mobile horizontal scroll feels broken
Problem: Pinned columns over-fill the viewport on small screens.
Solution: Conditionally disable pinning at < 768px (use VueUse's useMediaQuery).
Frequently asked questions
- Can users reorder pinned columns?
- Yes—Simple Table supports column reordering, including across the pinned/unpinned boundary. Set columnReordering="true".
- What about pinning rows (not just columns)?
- Row pinning is on the roadmap. Until then, render pinned rows in a separate header / footer slot.
- Does pinning work with virtualization?
- Yes. The pinned columns are rendered separately from the virtualized scroll area; performance is unchanged for 1M rows.
Wrap-up
Column pinning in Vue 3 is a single property on Simple Table. PrimeVue, Element Plus, and Naive UI support it natively too; Vuetify requires manual sticky CSS.
Cap the number of pinned columns and disable pinning on small viewports to keep the scrolling area usable.