Angular

Master Angular Table Column Reordering: The 2025 Guide

Unlock a superior user experience! Our 2025 guide teaches you to implement dynamic, persistent table column reordering in Angular using the CDK Drag & Drop.

D

Daniel Petrova

Senior Frontend Engineer specializing in creating dynamic, user-centric Angular applications.

7 min read16 views

Let’s be honest: static data tables feel like a relic from a bygone era. In 2025, users don’t just want to view data; they want to interact with it. They expect to sort, filter, and, most importantly, customize their workspace to fit their unique workflow. One of the most powerful, yet often overlooked, customizations is the ability to reorder table columns. It’s a subtle feature that screams “this application was built with me in mind.”

For a long time, implementing this seemingly simple drag-and-drop functionality in Angular felt like a chore. It involved complex event handling, DOM manipulation, and a mountain of custom code. But times have changed. Thanks to the Angular Component Dev Kit (CDK), building a fluid, intuitive, and persistent column reordering experience is more accessible than ever.

In this guide, we’ll dive deep into the modern way to master column reordering. We’ll go from a basic setup to a fully persistent, user-friendly implementation using the Angular CDK's Drag and Drop module. Get ready to give your users the control they crave and elevate your data tables from static displays to dynamic tools.

Why Column Reordering is a Game-Changer

Before we jump into the code, let's appreciate the why. Giving users the ability to reorder columns directly impacts the User Experience (UX) in several positive ways:

  • Personalization: Not all users care about the same data. A sales manager might want to see the 'Revenue' column first, while a support agent prioritizes the 'Last Contacted' column. Reordering allows for deep personalization.
  • Efficiency: Users can arrange data to match their mental model or workflow, reducing the cognitive load and time required to find information. Moving less important columns to the end declutters their immediate view.
  • Enhanced Engagement: Interactive elements make an application feel more alive and responsive. It’s a small detail that contributes to a feeling of quality and polish, encouraging users to engage more with the data.

Setting Up Your Angular Project for Success

First things first, let's get our environment ready. We'll start with a fresh Angular project and add the necessary dependencies.

1. Prerequisites: Ensure you have the Angular CLI and Node.js installed.

2. Create a New Project:

ng new angular-reorder-table --standalone false
cd angular-reorder-table

Note: We're using a non-standalone setup for this example for broader compatibility, but the principles are identical for standalone components.

3. Install Angular Material & CDK: The CDK is installed alongside Angular Material, which is the easiest way to get everything you need.

ng add @angular/material

The CLI will prompt you to choose a theme, set up typography, and include animations. Choose your preferred options.

4. Import the DragDropModule: Open your app.module.ts and import the DragDropModule from the CDK.

Advertisement
// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

import { DragDropModule } from '@angular/cdk/drag-drop'; // <-- Import this
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    DragDropModule // <-- Add it to your imports
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The Powerhouse: Angular CDK Drag and Drop

The Angular Component Dev Kit (CDK) is a set of tools that help you build awesome components without being tied to Material Design's specific styles. The DragDropModule is one of its crown jewels.

It gives us three key directives to work with:

  • cdkDropList: This directive turns a container element into a drop zone where draggable items can be placed.
  • cdkDrag: This directive makes an element within a cdkDropList draggable.
  • cdkDragHandle: An optional directive that allows you to specify a certain part of a cdkDrag element as the "handle" for dragging, rather than the entire element.

By combining these, we can create a powerful and flexible drag-and-drop system with minimal code.

Step-by-Step Implementation: Bringing it to Life

Let’s replace the default content in our AppComponent with a data table and make its columns reorderable.

The Component Logic (app.component.ts)

First, let's set up the TypeScript file. We need some sample data and, crucially, an array to define the order of our columns.

// src/app/app.component.ts
import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
  {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
  {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  columnsToDisplay: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.columnsToDisplay, event.previousIndex, event.currentIndex);
  }
}

The magic happens in the drop() method. It receives a CdkDragDrop event, which contains the previousIndex and currentIndex of the item being moved. We pass our columnsToDisplay array and these indices to the moveItemInArray utility function, which handles the reordering for us. It's that simple!

The Component Template (app.component.html)

Now, let's wire up the HTML. We'll create a standard HTML table and apply the CDK directives to the header row.

<!-- src/app/app.component.html -->
<h1>Interactive Angular Table</h1>

<table>
  <thead>
    <tr cdkDropList
        cdkDropListOrientation="horizontal"
        (cdkDropListDropped)="drop($event)">
      <th *ngFor="let column of columnsToDisplay" cdkDrag>{{column}}</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let element of dataSource">
      <td *ngFor="let column of columnsToDisplay">
        {{element[column]}}
      </td>
    </tr>
  </tbody>
</table>

Let's break this down:

  1. <tr cdkDropList ...>: We make the header row our drop zone. cdkDropListOrientation="horizontal" tells the CDK to only allow horizontal dragging.
  2. (cdkDropListDropped)="drop($event)": This binds the drop event to our component's drop() method.
  3. <th *ngFor="let column of columnsToDisplay" cdkDrag>: We loop through our dynamic columnsToDisplay array to create the header cells and make each one (<th>) draggable with the cdkDrag directive.
  4. <td *ngFor="let column of columnsToDisplay">: This is the crucial link. The table body's cells are also rendered based on the same columnsToDisplay array. When the array is reordered, the data cells automatically follow suit!

Add some basic styling to app.component.css to make it look like a table, and you're good to go!

/* src/app/app.component.css */
table {
  width: 100%;
  border-collapse: collapse;
}
th, td {
  border: 1px solid #ccc;
  padding: 8px;
  text-align: left;
}
th {
  background-color: #f2f2f2;
  cursor: move;
}

/* Styling for the CDK drag-and-drop effects */
.cdk-drag-preview {
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
              0 8px 10px 1px rgba(0, 0, 0, 0.14),
              0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
  opacity: 0;
}

Run ng serve, and you should have a fully functional, reorderable table column header!

Making it Stick: Persisting the Column Order

A reordering feature is great, but it's frustrating for users if it resets every time they refresh the page. Let's add persistence using the browser's localStorage.

We'll modify our app.component.ts in two places:

1. Save the order after a drop:

  // ... inside AppComponent
  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.columnsToDisplay, event.previousIndex, event.currentIndex);
    // Save the new order to localStorage
    localStorage.setItem('tableColumns', JSON.stringify(this.columnsToDisplay));
  }

2. Load the order on initialization:

We'll use the ngOnInit lifecycle hook to check for a saved order when the component loads.

// ... inside AppComponent
import { Component, OnInit } from '@angular/core'; // Add OnInit

// ...

export class AppComponent implements OnInit { // Implement OnInit
  columnsToDisplay: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;

  ngOnInit() {
    const savedColumns = localStorage.getItem('tableColumns');
    if (savedColumns) {
      this.columnsToDisplay = JSON.parse(savedColumns);
    }
  }

  drop(event: CdkDragDrop<string[]>) {
    // ... (same as before)
  }
}

Now, when a user reorders the columns, their preference is saved. The next time they visit the page, the table will load with their custom layout. It’s a massive UX win for minimal effort.

Advanced Tips & Common Pitfalls

  • Styling Hooks: The CDK adds helpful CSS classes during drag operations. You can style .cdk-drag-preview (the ghost element you're dragging) and .cdk-drag-placeholder (the empty space left behind) for a more polished look.
  • Accessibility (a11y): While drag-and-drop is great, it's not accessible to all users. Consider adding a complementary "Column Settings" dialog where users can reorder columns using keyboard-accessible buttons (e.g., up/down arrows) or a multi-select list.
  • Common Pitfall #1: Forgetting the Module. If drag-and-drop isn't working at all, your first check should be ensuring DragDropModule is correctly imported into the relevant NgModule or standalone component.
  • Common Pitfall #2: Forgetting to Sync Body Columns. A frequent mistake is only reordering the headers. The key is to use the same dynamic array (columnsToDisplay) to render both the <th> elements and the <td> elements in each data row.

Conclusion: Your Users Will Thank You

You've now seen how straightforward it is to implement dynamic table column reordering in a modern Angular application. By leveraging the power of the Angular CDK, you can move beyond static data displays and create truly interactive, user-centric experiences.

We've covered the entire process: setting up the project, implementing the core drag-and-drop logic with moveItemInArray, and persisting the user's choices with localStorage. This single feature can significantly boost user satisfaction and efficiency in any data-heavy application. So go ahead, add it to your project, and watch your users delight in the control you've given them.

Tags

You May Also Like