How to sort tables in Angular
Sortable tables help users find data quickly by ordering rows based on any column. As the creator of CoreUI with over 10 years of Angular experience since 2014, I’ve built sortable data tables for enterprise dashboards handling thousands of rows. The most effective approach tracks sort column and direction in component state, uses a getter to return sorted data, and shows directional indicators on column headers. This provides intuitive sorting without external libraries.
Add sorting to a table with column click handlers.
import { Component } from '@angular/core'
import { CommonModule } from '@angular/common'
type SortDir = 'asc' | 'desc'
@Component({
selector: 'app-sortable-table',
standalone: true,
imports: [CommonModule],
template: `
<table>
<thead>
<tr>
<th (click)="sort('name')" class="sortable">
Name {{ indicator('name') }}
</th>
<th (click)="sort('age')" class="sortable">
Age {{ indicator('age') }}
</th>
<th (click)="sort('email')" class="sortable">
Email {{ indicator('email') }}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of sortedRows">
<td>{{ row.name }}</td>
<td>{{ row.age }}</td>
<td>{{ row.email }}</td>
</tr>
</tbody>
</table>
`,
styles: [`
.sortable { cursor: pointer; user-select: none; }
.sortable:hover { background: #f0f0f0; }
`]
})
export class SortableTableComponent {
rows = [
{ name: 'Alice', age: 30, email: '[email protected]' },
{ name: 'Charlie', age: 25, email: '[email protected]' },
{ name: 'Bob', age: 35, email: '[email protected]' }
]
sortColumn: string | null = null
sortDir: SortDir = 'asc'
sort(column: string) {
if (this.sortColumn === column) {
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc'
} else {
this.sortColumn = column
this.sortDir = 'asc'
}
}
indicator(column: string): string {
if (this.sortColumn !== column) return '↕'
return this.sortDir === 'asc' ? '↑' : '↓'
}
get sortedRows() {
if (!this.sortColumn) return this.rows
return [...this.rows].sort((a, b) => {
const aVal = (a as any)[this.sortColumn!]
const bVal = (b as any)[this.sortColumn!]
const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0
return this.sortDir === 'asc' ? cmp : -cmp
})
}
}
Clicking a column header calls sort(). Clicking the same column again reverses direction. The indicator() method returns the correct arrow character. The sortedRows getter returns a sorted copy without mutating the original array.
Sorting with Multiple Column Types
Handle numbers, dates, and strings correctly.
get sortedRows() {
if (!this.sortColumn) return this.rows
return [...this.rows].sort((a, b) => {
const aVal = (a as any)[this.sortColumn!]
const bVal = (b as any)[this.sortColumn!]
let cmp = 0
if (typeof aVal === 'number') {
cmp = aVal - bVal
} else if (aVal instanceof Date) {
cmp = aVal.getTime() - bVal.getTime()
} else {
cmp = String(aVal).localeCompare(String(bVal))
}
return this.sortDir === 'asc' ? cmp : -cmp
})
}
Numbers sort arithmetically for correct ordering. Dates compare timestamps. Strings use localeCompare for proper alphabetical sorting including accented characters. Detect the type dynamically.
Server-Side Sorting
Request sorted data from the API.
import { Component, OnInit } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { CommonModule } from '@angular/common'
@Component({
selector: 'app-server-sorted-table',
standalone: true,
imports: [CommonModule],
template: `
<table>
<thead>
<tr>
<th (click)="sort('name')">Name {{ indicator('name') }}</th>
<th (click)="sort('age')">Age {{ indicator('age') }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows">
<td>{{ row.name }}</td>
<td>{{ row.age }}</td>
</tr>
</tbody>
</table>
`
})
export class ServerSortedTableComponent implements OnInit {
rows: any[] = []
sortColumn = 'name'
sortDir: SortDir = 'asc'
constructor(private http: HttpClient) {}
ngOnInit() { this.loadData() }
sort(column: string) {
if (this.sortColumn === column) {
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc'
} else {
this.sortColumn = column
this.sortDir = 'asc'
}
this.loadData()
}
indicator(col: string) {
if (this.sortColumn !== col) return '↕'
return this.sortDir === 'asc' ? '↑' : '↓'
}
loadData() {
this.http
.get<any[]>(`/api/users?sort=${this.sortColumn}&dir=${this.sortDir}`)
.subscribe(data => this.rows = data)
}
}
Each column click triggers an API request with the sort parameters. The server handles sorting, enabling efficient sorting of millions of rows. Use this when data doesn’t fit in memory.
Best Practice Note
This is the same sorting pattern we use in CoreUI Angular tables. For client-side sorting, always sort a copy of the array with spread operator to preserve the original. For large datasets over ~10,000 rows, switch to server-side sorting. Consider using CoreUI’s CTable component which includes built-in sortable columns with accessibility features. Add aria-sort attributes to headers for screen reader compatibility.



