DataGrid Column Reordering
Drag DataGrid columns into a new visible order and persist the reordered column model.
Column Reordering
Drag header grips to change column order
Column reordering is disabled by default. Turn it on with [columnReorderable]="true" and drag the grip icon at the start of a header cell. The handle stays visible so developers can see where dragging starts. The SKU column has reorderable: false so it always stays first. Use (columnReorder) to read the new field order after each drop.
Header drag reorder
Drag any header except SKU. Sorting still works on sortable columns.
Loading interactive DataGrid example…
Action-driven reorder
Use reorderColumn() when column order should change from a toolbar, menu, or settings panel. Pass the column (or field name), the destination visible index, and whether to insert before or after that index. Only visible columns can be moved.
Loading interactive DataGrid example…
API reference
| Option | Scope | Description |
|---|---|---|
[columnReorderable] | Grid | Enables reordering (drag handles and API). Default false. |
(columnReorder) | Grid output | Fires after drag or API reorder. Payload: NgbColumnReorderEvent with column, fromIndex, toIndex, fields, and columns. |
reorderColumn(column, index, options?) | Grid API | Move a visible column relative to index. Options: { before: true } (default) inserts before; { before: false } inserts after. |
moveColumn(from, to) | Grid API | Reorder by visible column indices (same rules as a header drop target). |
ColumnDef.reorderable | Column | Set false to keep a column fixed while others reorder around it. |
Limitations
- Not available when the grid uses stacked card layout.
- Disabled when any visible column is
lockedor pinned (sticky).
Column reordering
Integration steps
- Set [columnReorderable]="true" on ngb-datagrid. Reordering is disabled by default.
- Drag the grip handle at the start of a header cell to move that column.
- Listen to (columnReorder) to persist order in your app state or backend.
- Set ColumnDef.reorderable to false on columns that must stay fixed (for example an ID column).
- Column reorder is not available in stacked card layout or when any column is locked or pinned.
Component
@Component({
imports: [Datagrid],
template: `
<p *ngIf="lastReorder">Order: {{ lastReorder.fields.join(' → ') }}</p>
<ngb-datagrid
[columns]="columns"
[data]="rows"
[columnReorderable]="true"
[enableSorting]="true"
(columnReorder)="onColumnReorder($event)"
></ngb-datagrid>
`,
})
export class ProductGridReorderDemo {
lastReorder: { fields: string[] } | null = null;
readonly columns: ColumnDef<ProductRow>[] = [
{ field: 'sku', header: 'SKU', reorderable: false },
{ field: 'product', header: 'Product' },
{ field: 'category', header: 'Category' },
{ field: 'price', header: 'Price', type: 'number' },
];
onColumnReorder(event: { fields: string[] }): void {
this.lastReorder = { fields: event.fields };
}
}
Declarative column
<ngb-grid-column
field="sku"
header="SKU"
[reorderable]="false"
></ngb-grid-column>
Programmatic column reorder
Integration steps
- Keep [columnReorderable]="true" so the grid maintains column order state.
- Obtain a ViewChild reference to the Datagrid instance.
- Call reorderColumn(column, destinationIndex, { before: true | false }) from a button or menu handler.
- Pass a ColumnDef or field name for the column to move; only visible columns can be reordered.
- Listen to (columnReorder) when you need to sync order with external state.
Component
@Component({
imports: [Datagrid],
template: `
<div class="btn-group btn-group-sm mb-2">
<button type="button" class="btn btn-outline-primary" (click)="moveStatusToFront()">
Move Status to front
</button>
<button type="button" class="btn btn-outline-secondary" (click)="placeUnitsAfterWarehouse()">
Place Units after Warehouse
</button>
</div>
<ngb-datagrid
#inventoryGrid
[columns]="columns"
[data]="rows"
[columnReorderable]="true"
(columnReorder)="onColumnReorder($event)"
></ngb-datagrid>
`,
})
export class InventoryColumnReorderDemo {
@ViewChild('inventoryGrid') grid?: Datagrid<InventoryRow>;
readonly columns: ColumnDef<InventoryRow>[] = [
{ field: 'itemCode', header: 'Item Code' },
{ field: 'warehouse', header: 'Warehouse' },
{ field: 'region', header: 'Region' },
{ field: 'units', header: 'Units', type: 'number' },
{ field: 'status', header: 'Status' },
];
moveStatusToFront(): void {
this.grid?.reorderColumn('status', 0, { before: true });
}
placeUnitsAfterWarehouse(): void {
const warehouseIndex = this.grid?.visibleColumns.findIndex((col) => col.field === 'warehouse') ?? -1;
if (warehouseIndex < 0) return;
this.grid?.reorderColumn('units', warehouseIndex, { before: false });
}
}
API calls
// Move the last visible column before the first column
grid.reorderColumn('status', 0, { before: true });
// Insert after the column at index 1
grid.reorderColumn(statusColumn, 1, { before: false });