Pinned Columns Plugin
The Pinned Columns plugin freezes columns to the left or right edge of the grid—essential for keeping key identifiers or action buttons visible while scrolling through wide datasets. Just set pinned: 'left' or pinned: 'right' on your column definitions and the plugin handles the rest.
Installation
Section titled “Installation”import '@toolbox-web/grid/features/pinned-columns';Basic Usage
Section titled “Basic Usage”Pin important columns like ID on the left and action buttons on the right. The pinned columns stay fixed while the middle content scrolls horizontally.
import { queryGrid } from '@toolbox-web/grid';
const grid = queryGrid('tbw-grid');grid.gridConfig = { columns: [ { field: 'id', header: 'ID', pinned: 'left', width: 80 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, { field: 'department', header: 'Department' }, { field: 'salary', header: 'Salary', type: 'currency' }, { field: 'actions', header: 'Actions', pinned: 'right', width: 120 }, ], features: { pinnedColumns: true },};import '@toolbox-web/grid-react/features/pinned-columns';import { DataGrid } from '@toolbox-web/grid-react';
function EmployeeGrid({ employees }) { return ( <DataGrid rows={employees} columns={[ { field: 'id', header: 'ID', pinned: 'left', width: 80 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, { field: 'department', header: 'Department' }, { field: 'salary', header: 'Salary', type: 'currency' }, { field: 'actions', header: 'Actions', pinned: 'right', width: 120 }, ]} pinnedColumns /> );}<script setup>import '@toolbox-web/grid-vue/features/pinned-columns';import { TbwGrid } from '@toolbox-web/grid-vue';
const employees = [ { id: 1, name: 'Alice', email: 'alice@example.com', department: 'Engineering', salary: 95000 }, { id: 2, name: 'Bob', email: 'bob@example.com', department: 'Marketing', salary: 75000 },];
const columns = [ { field: 'id', header: 'ID', pinned: 'left', width: 80 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, { field: 'department', header: 'Department' }, { field: 'salary', header: 'Salary', type: 'currency' }, { field: 'actions', header: 'Actions', pinned: 'right', width: 120 },];</script>
<template> <TbwGrid :rows="employees" :columns="columns" pinned-columns /></template>// Feature import - enables the [pinnedColumns] inputimport '@toolbox-web/grid-angular/features/pinned-columns';
import { Component } from '@angular/core';import { Grid } from '@toolbox-web/grid-angular';import type { ColumnConfig } from '@toolbox-web/grid';
@Component({ selector: 'app-employee-grid', imports: [Grid], template: ` <tbw-grid [rows]="rows" [columns]="columns" [pinnedColumns]="true" style="height: 400px; display: block;"> </tbw-grid> `,})export class EmployeeGridComponent { rows = [];
columns: ColumnConfig[] = [ { field: 'id', header: 'ID', pinned: 'left', width: 80 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, { field: 'department', header: 'Department' }, { field: 'salary', header: 'Salary', type: 'currency' }, { field: 'actions', header: 'Actions', pinned: 'right', width: 120 }, ];}<tbw-grid style="height: 500px;"></tbw-grid>import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';import '@toolbox-web/grid/features/pinned-columns';
const FIRST_NAMES = ['Alice', 'Bob', 'Carol', 'Dan', 'Eve', 'Frank', 'Grace', 'Henry', 'Ivy', 'Jack'];const LAST_NAMES = ['Johnson', 'Smith', 'Williams', 'Brown', 'Jones', 'Davis', 'Miller', 'Wilson', 'Moore', 'Taylor'];const DEPARTMENTS = ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance', 'Legal', 'Support', 'Design'];const CITIES = ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'Dallas'];const COUNTRIES = ['USA', 'Canada', 'UK', 'Germany', 'France', 'Australia', 'Japan', 'Brazil'];
function generateRows(count: number) { const rows = []; for (let i = 0; i < count; i++) { const first = FIRST_NAMES[i % FIRST_NAMES.length]; const last = LAST_NAMES[Math.floor(i / FIRST_NAMES.length) % LAST_NAMES.length]; rows.push({ id: i + 1, name: `${first} ${last}`, email: `${first.toLowerCase()}.${last.toLowerCase()}@example.com`, department: DEPARTMENTS[i % DEPARTMENTS.length], phone: `+1-555-${String(i).padStart(4, '0')}`, address: `${100 + i} ${['Main', 'Oak', 'Pine', 'Elm', 'Maple'][i % 5]} St`, city: CITIES[i % CITIES.length], country: COUNTRIES[i % COUNTRIES.length], actions: '...', }); } return rows;}
function toPinned(value: string) { return value === 'none' ? undefined : value;}
const sampleData = generateRows(1000);const grid = queryGrid('tbw-grid')!;
function rebuild(pins: Record<string, string>) { grid.gridConfig = { columns: [ { field: 'id', header: 'ID', type: 'number', width: 60, pinned: toPinned(pins.pinId ?? 'left') }, { field: 'name', header: 'Name', width: 150, pinned: toPinned(pins.pinName ?? 'left') }, { field: 'email', header: 'Email', width: 220, pinned: toPinned(pins.pinEmail ?? 'none') }, { field: 'department', header: 'Department', width: 150, pinned: toPinned(pins.pinDepartment ?? 'none') }, { field: 'phone', header: 'Phone', width: 150, pinned: toPinned(pins.pinPhone ?? 'none') }, { field: 'address', header: 'Address', width: 250, pinned: toPinned(pins.pinAddress ?? 'none') }, { field: 'city', header: 'City', width: 120, pinned: toPinned(pins.pinCity ?? 'none') }, { field: 'country', header: 'Country', width: 120, pinned: toPinned(pins.pinCountry ?? 'none') }, { field: 'actions', header: 'Actions', width: 100, pinned: toPinned(pins.pinActions ?? 'right') }, ], fitMode: 'fixed', features: { pinnedColumns: true }, }; grid.rows = sampleData;}
rebuild({});Use the controls below to change which columns are pinned to the left, right, or not pinned. Pinned columns are automatically reordered to the grid edges—left-pinned columns move to the start, right-pinned columns move to the end. Unpinning restores the column to its original position.
Configuration Options
Section titled “Configuration Options”The plugin has no configuration options. It is activated when columns have pinned: 'left' or pinned: 'right' set.
Programmatic API
Section titled “Programmatic API”See PinnedColumnsPlugin for the full list of methods.
const plugin = grid.getPluginByName('pinnedColumns');
// Get currently pinned columnsconst leftPinned = plugin.getLeftPinnedColumns();const rightPinned = plugin.getRightPinnedColumns();
// Clear all sticky positionsplugin.clearStickyPositions();
// Recalculate offsets (e.g., after column resize)plugin.refreshStickyOffsets();RTL Support
Section titled “RTL Support”For direction-independent pinning, use logical values 'start' and 'end' instead of 'left'/'right':
{ field: 'id', pinned: 'start' } // Left in LTR, Right in RTL{ field: 'actions', pinned: 'end' } // Right in LTR, Left in RTLColumn Reordering Behaviour
Section titled “Column Reordering Behaviour”When a column is pinned (either via config or the context menu), the plugin automatically reorders it to the appropriate edge of the grid:
pinned: 'left'→ moved to the leftmost position (after other left-pinned columns)pinned: 'right'→ moved to the rightmost position (before other right-pinned columns)
When a column is unpinned via the context menu, it is restored to its original position in the column order.
This ensures pinned columns are always visible at the grid edges without requiring the user to scroll.
Known Limitations
Section titled “Known Limitations”-
Incompatible with Column Groups: Pinned columns cannot be used together with the Column Groups plugin. Pinning reorders columns to the grid edges, but moving a column out of its column group is not supported. When both plugins are loaded, a development-mode warning is shown and the pin/unpin context menu items are hidden.
-
Header-only sticky in virtualized grids: Due to the row virtualization architecture (
will-change: transformon the rows container),position: stickyonly works on header cells. Data row cells receive the sticky CSS classes but the browser cannot honour them because the transformed ancestor creates a new containing block.
See Also
Section titled “See Also”- Pinned Rows — Pin rows to top/bottom
- Column Reorder — Drag-to-reorder columns
- Column Groups — Group column headers