Documentation
Column Sorting
Column sorting allows users to organize table data in ascending or descending order based on column values. This feature is essential for data analysis and quick information retrieval.
1import {SimpleTable} from "@simple-table/react";import type { Theme } from "@simple-table/react";2import { columnSortingConfig } from "./column-sorting.demo-data";3import "@simple-table/react/styles.css";45const ColumnSortingDemo = ({6 height = "400px",7 theme,8}: {9 height?: string | number;10 theme?: Theme;11}) => {12 return (13 <SimpleTable14 defaultHeaders={columnSortingConfig.headers}15 rows={columnSortingConfig.rows}16 height={height}17 theme={theme}18 initialSortColumn={columnSortingConfig.tableProps.initialSortColumn}19 initialSortDirection={columnSortingConfig.tableProps.initialSortDirection}20 />21 );22};2324export default ColumnSortingDemo;
1<template>2 <SimpleTable3 :default-headers="columnSortingConfig.headers"4 :rows="columnSortingConfig.rows"5 :height="height"6 :theme="theme"7 :initial-sort-column="columnSortingConfig.tableProps.initialSortColumn"8 :initial-sort-direction="columnSortingConfig.tableProps.initialSortDirection"9 />10</template>1112<script setup lang="ts">13import {SimpleTable} from "@simple-table/vue";import type { Theme } from "@simple-table/vue";14import { columnSortingConfig } from "./column-sorting.demo-data";15import "@simple-table/vue/styles.css";1617withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {18 height: "400px",19});20</script>
1import { Component, Input } from "@angular/core";2import {SimpleTableComponent} from "@simple-table/angular";import type { AngularHeaderObject, Row, Theme } from "@simple-table/angular";3import { columnSortingConfig } from "./column-sorting.demo-data";4import "@simple-table/angular/styles.css";56@Component({7 selector: "column-sorting-demo",8 standalone: true,9 imports: [SimpleTableComponent],10 template: `11 <simple-table12 [rows]="rows"13 [defaultHeaders]="headers"14 [height]="height"15 [theme]="theme"16 [initialSortColumn]="initialSortColumn"17 [initialSortDirection]="initialSortDirection"18 ></simple-table>19 `,20})21export class ColumnSortingDemoComponent {22 @Input() height: string | number = "400px";23 @Input() theme?: Theme;2425 readonly rows: Row[] = columnSortingConfig.rows;26 readonly headers: AngularHeaderObject[] = columnSortingConfig.headers;27 readonly initialSortColumn = columnSortingConfig.tableProps.initialSortColumn;28 readonly initialSortDirection = columnSortingConfig.tableProps.initialSortDirection;29}303132// column-sorting.demo-data.ts33// Self-contained demo table setup for this example.34import type { Row } from "@simple-table/angular";35import type { AngularHeaderObject } from "@simple-table/angular";363738export const COLUMN_SORTING_DATA: Row[] = [39 {40 id: 1,41 name: "Dr. Elena Vasquez",42 age: 42,43 role: "Computer Science Professor",44 department: "Computer Science",45 startDate: "2015-08-15",46 },47 {48 id: 2,49 name: "Prof. Michael Chang",50 age: 38,51 role: "Mathematics Professor",52 department: "Mathematics",53 startDate: "2017-01-10",54 },55 {56 id: 3,57 name: "Dr. Sarah Mitchell",58 age: 45,59 role: "Dean of Engineering",60 department: "Administration",61 startDate: "2012-09-01",62 },63 {64 id: 4,65 name: "Alex Parker",66 age: 22,67 role: "Graduate Student",68 department: "Computer Science",69 startDate: "2023-09-01",70 },71 {72 id: 5,73 name: "Dr. James Wilson",74 age: 51,75 role: "Physics Professor",76 department: "Physics",77 startDate: "2008-03-15",78 },79 {80 id: 6,81 name: "Maria Santos",82 age: 24,83 role: "Research Assistant",84 department: "Biology",85 startDate: "2022-06-01",86 },87 {88 id: 7,89 name: "Prof. David Kumar",90 age: 39,91 role: "Biology Professor",92 department: "Biology",93 startDate: "2018-02-14",94 },95 {96 id: 8,97 name: "Rachel Green",98 age: 28,99 role: "Lab Coordinator",100 department: "Chemistry",101 startDate: "2020-11-05",102 },103 {104 id: 9,105 name: "Dr. Lisa Chen",106 age: 47,107 role: "Psychology Professor",108 department: "Psychology",109 startDate: "2014-08-20",110 },111 {112 id: 10,113 name: "Ben Taylor",114 age: 23,115 role: "Teaching Assistant",116 department: "Mathematics",117 startDate: "2023-01-15",118 },119 {120 id: 11,121 name: "Dr. Anna Rodriguez",122 age: 35,123 role: "Chemistry Professor",124 department: "Chemistry",125 startDate: "2019-07-01",126 },127 {128 id: 12,129 name: "Prof. Robert Kim",130 age: 44,131 role: "Department Head",132 department: "Engineering",133 startDate: "2011-04-12",134 },135];136137138export const columnSortingHeaders: AngularHeaderObject[] = [139 { accessor: "id", label: "ID", width: 80, isSortable: true, type: "number" },140 { accessor: "name", label: "Name", width: 180, isSortable: true, type: "string" },141 { accessor: "age", label: "Age", width: 80, isSortable: true, type: "number" },142 { accessor: "role", label: "Role", width: 200, isSortable: true, type: "string" },143 {144 accessor: "department",145 label: "Department",146 width: 180,147 isSortable: true,148 type: "string",149 valueFormatter: ({ value }) => {150 return (value as string).charAt(0).toUpperCase() + (value as string).slice(1);151 },152 },153 {154 accessor: "startDate",155 label: "Start Date",156 width: 140,157 isSortable: true,158 type: "date",159 valueFormatter: ({ value }) => {160 if (typeof value === "string") {161 return new Date(value).toLocaleDateString("en-US", {162 year: "numeric",163 month: "short",164 day: "numeric",165 });166 }167 return String(value);168 },169 },170];171172export const columnSortingConfig = {173 headers: columnSortingHeaders,174 rows: COLUMN_SORTING_DATA,175 tableProps: {176 initialSortColumn: "age",177 initialSortDirection: "desc" as const,178 },179} as const;180
1<script lang="ts">2 import {SimpleTable} from "@simple-table/svelte"; import type { Theme } from "@simple-table/svelte";3 import { columnSortingConfig } from "./column-sorting.demo-data";4 import "@simple-table/svelte/styles.css";56 let { height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();7</script>89<SimpleTable10 defaultHeaders={columnSortingConfig.headers}11 rows={columnSortingConfig.rows}12 {height}13 {theme}14 initialSortColumn={columnSortingConfig.tableProps.initialSortColumn}15 initialSortDirection={columnSortingConfig.tableProps.initialSortDirection}16/>
1import {SimpleTable} from "@simple-table/solid";import type { Theme } from "@simple-table/solid";2import { columnSortingConfig } from "./column-sorting.demo-data";3import "@simple-table/solid/styles.css";45export default function ColumnSortingDemo(props: {6 height?: string | number;7 theme?: Theme;8}) {9 return (10 <SimpleTable11 defaultHeaders={columnSortingConfig.headers}12 rows={columnSortingConfig.rows}13 height={props.height ?? "400px"}14 theme={props.theme}15 initialSortColumn={columnSortingConfig.tableProps.initialSortColumn}16 initialSortDirection={columnSortingConfig.tableProps.initialSortDirection}17 />18 );19}
1import { SimpleTableVanilla } from "simple-table-core";2import type { Theme } from "simple-table-core";3import { columnSortingConfig } from "./column-sorting.demo-data";4import "simple-table-core/styles.css";56export function renderColumnSortingDemo(7 container: HTMLElement,8 options?: { height?: string | number; theme?: Theme }9): SimpleTableVanilla {10 const table = new SimpleTableVanilla(container, {11 defaultHeaders: columnSortingConfig.headers,12 rows: columnSortingConfig.rows,13 height: options?.height ?? "400px",14 theme: options?.theme,15 initialSortColumn: columnSortingConfig.tableProps.initialSortColumn,16 initialSortDirection: columnSortingConfig.tableProps.initialSortDirection,17 });18 return table;19}202122// column-sorting.demo-data.ts23// Self-contained demo table setup for this example.24import type { Row } from "simple-table-core";25import type { HeaderObject } from "simple-table-core";262728export const COLUMN_SORTING_DATA: Row[] = [29 {30 id: 1,31 name: "Dr. Elena Vasquez",32 age: 42,33 role: "Computer Science Professor",34 department: "Computer Science",35 startDate: "2015-08-15",36 },37 {38 id: 2,39 name: "Prof. Michael Chang",40 age: 38,41 role: "Mathematics Professor",42 department: "Mathematics",43 startDate: "2017-01-10",44 },45 {46 id: 3,47 name: "Dr. Sarah Mitchell",48 age: 45,49 role: "Dean of Engineering",50 department: "Administration",51 startDate: "2012-09-01",52 },53 {54 id: 4,55 name: "Alex Parker",56 age: 22,57 role: "Graduate Student",58 department: "Computer Science",59 startDate: "2023-09-01",60 },61 {62 id: 5,63 name: "Dr. James Wilson",64 age: 51,65 role: "Physics Professor",66 department: "Physics",67 startDate: "2008-03-15",68 },69 {70 id: 6,71 name: "Maria Santos",72 age: 24,73 role: "Research Assistant",74 department: "Biology",75 startDate: "2022-06-01",76 },77 {78 id: 7,79 name: "Prof. David Kumar",80 age: 39,81 role: "Biology Professor",82 department: "Biology",83 startDate: "2018-02-14",84 },85 {86 id: 8,87 name: "Rachel Green",88 age: 28,89 role: "Lab Coordinator",90 department: "Chemistry",91 startDate: "2020-11-05",92 },93 {94 id: 9,95 name: "Dr. Lisa Chen",96 age: 47,97 role: "Psychology Professor",98 department: "Psychology",99 startDate: "2014-08-20",100 },101 {102 id: 10,103 name: "Ben Taylor",104 age: 23,105 role: "Teaching Assistant",106 department: "Mathematics",107 startDate: "2023-01-15",108 },109 {110 id: 11,111 name: "Dr. Anna Rodriguez",112 age: 35,113 role: "Chemistry Professor",114 department: "Chemistry",115 startDate: "2019-07-01",116 },117 {118 id: 12,119 name: "Prof. Robert Kim",120 age: 44,121 role: "Department Head",122 department: "Engineering",123 startDate: "2011-04-12",124 },125];126127128export const columnSortingHeaders: HeaderObject[] = [129 { accessor: "id", label: "ID", width: 80, isSortable: true, type: "number" },130 { accessor: "name", label: "Name", width: 180, isSortable: true, type: "string" },131 { accessor: "age", label: "Age", width: 80, isSortable: true, type: "number" },132 { accessor: "role", label: "Role", width: 200, isSortable: true, type: "string" },133 {134 accessor: "department",135 label: "Department",136 width: 180,137 isSortable: true,138 type: "string",139 valueFormatter: ({ value }) => {140 return (value as string).charAt(0).toUpperCase() + (value as string).slice(1);141 },142 },143 {144 accessor: "startDate",145 label: "Start Date",146 width: 140,147 isSortable: true,148 type: "date",149 valueFormatter: ({ value }) => {150 if (typeof value === "string") {151 return new Date(value).toLocaleDateString("en-US", {152 year: "numeric",153 month: "short",154 day: "numeric",155 });156 }157 return String(value);158 },159 },160];161162export const columnSortingConfig = {163 headers: columnSortingHeaders,164 rows: COLUMN_SORTING_DATA,165 tableProps: {166 initialSortColumn: "age",167 initialSortDirection: "desc" as const,168 },169} as const;170
Basic Sorting
To enable sorting for a column, add the isSortable: true property to your column definition.
✨ New in v1.9.4: Array Index Support
Accessors now support nested array paths using bracket notation. This allows you to sort by specific array elements without writing custom logic.
awards[0]- Sort by first awardalbums[0].title- Sort by first album's titlereleaseDate[0]- Sort by first release date
Column Sorting Configuration
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
HeaderObject.isSortableboolean | Optional | Enables sorting functionality for the column. When true, users can click the column header to sort data. | |
HeaderObject.sortingOrderArray<'asc' | 'desc' | null> | Optional | Custom sort order cycle for this column. Defines the sequence of sort states when clicking the column header. Default is ['asc', 'desc', null] which cycles through ascending → descending → no sort. Customize per column based on data type - use ['desc', 'asc', null] for numbers/dates where descending is more common. | |
HeaderObject.comparator | Optional | Custom sorting function based on row-level metadata or complex logic. Receives full row objects and sort direction, allowing you to sort by multiple fields, nested properties, or domain-specific rules. | |
HeaderObject.valueGetter | Optional | Function to extract values from nested objects or compute values dynamically for sorting operations. Useful when the displayed value differs from the sorting value, or when sorting by deeply nested properties. |
Custom Sort Order
Customize the sort cycle for individual columns using the sortingOrder property. This allows different columns to have different sort behaviors based on their data type and expected user interaction patterns.
💡 Common Patterns
- Numbers/Dates: Use
['desc', 'asc', null]to show highest values or most recent dates first - Text/Names: Use
['asc', 'desc', null](default) for alphabetical sorting - Always Sorted: Use
['asc', 'desc']to prevent removing sort (no null state) - Single Direction: Use
['desc', null]to toggle between descending and no sort
Advanced Sorting
For complex sorting scenarios, Simple Table provides two powerful options:
Custom Comparator
Use comparator when you need to sort based on multiple fields, row metadata, or custom business logic:
💡 Use Cases
- Sort by multiple fields with priority (e.g., priority level + performance score)
- Access metadata or related fields not directly in the column
- Implement domain-specific sorting rules (e.g., custom status ordering)
- Sort by computed values derived from multiple row properties
Value Getter
Use valueGetter to extract nested values or compute values for sorting, especially when displaying formatted text:
💡 Use Cases
- Sort by nested/computed values while displaying formatted text
- Access deeply nested properties (e.g., row.metadata.seniorityLevel)
- Calculate derived values for sorting operations
- Combine with valueFormatter to separate sorting logic from display
🎯 Comparator vs ValueGetter
Use comparator when you need full control over the sorting logic with access to both rows. Use valueGetter when you want the default sorting behavior but need to extract or compute the value first.
Initial Sort State
Set the table to load with a default sort applied using initialSortColumn and initialSortDirection. This is perfect for showing users the most relevant data first, like sorting by date (newest first) or revenue (highest first).
💡 Use Cases
- Sort by date to show newest records first
- Sort by revenue/sales to highlight top performers
- Sort by priority or status to show critical items first
- Provide a consistent, predictable initial view for users
The table will load with the sort applied, and users can still change the sort by clicking column headers.
External Sorting
For advanced use cases, you can handle sorting externally - perfect for server-side sorting, API integration, or custom sorting logic. This demo shows how to manage sorting completely outside the table component.
External Sort Status: No sorting applied
1import { useState, useMemo } from "react";2import {SimpleTable} from "@simple-table/react";import type { Theme, SortColumn } from "@simple-table/react";3import { externalSortConfig } from "./external-sort.demo-data";4import "@simple-table/react/styles.css";56const ExternalSortDemo = ({7 height = "400px",8 theme,9}: {10 height?: string | number;11 theme?: Theme;12}) => {13 const [sortConfig, setSortConfig] = useState<SortColumn | null>(null);1415 const sortedData = useMemo(() => {16 if (!sortConfig) return externalSortConfig.rows;17 const sorted = [...externalSortConfig.rows].sort((a, b) => {18 const key = sortConfig.key.accessor;19 const aVal = a[key as keyof typeof a];20 const bVal = b[key as keyof typeof b];21 if (aVal === bVal) return 0;22 const cmp =23 sortConfig.key.type === "number"24 ? (aVal as number) - (bVal as number)25 : String(aVal).localeCompare(String(bVal));26 return sortConfig.direction === "asc" ? cmp : -cmp;27 });28 return sorted;29 }, [sortConfig]);3031 return (32 <SimpleTable33 defaultHeaders={externalSortConfig.headers}34 rows={sortedData}35 onSortChange={setSortConfig}36 externalSortHandling37 columnResizing38 height={height}39 theme={theme}40 />41 );42};4344export default ExternalSortDemo;
1<template>2 <SimpleTable3 :default-headers="externalSortConfig.headers"4 :rows="sortedRows"5 :external-sort-handling="true"6 :column-resizing="externalSortConfig.tableProps.columnResizing"7 :height="height"8 :theme="theme"9 @sort-change="handleSortChange"10 />11</template>1213<script setup lang="ts">14import { ref, computed } from "vue";15import {SimpleTable} from "@simple-table/vue";import type { Theme, SortColumn } from "@simple-table/vue";16import { externalSortConfig } from "./external-sort.demo-data";17import "@simple-table/vue/styles.css";1819withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {20 height: "400px",21});2223const sortConfig = ref<SortColumn | null>(null);2425const sortedRows = computed(() => {26 const data = [...externalSortConfig.rows];27 const sort = sortConfig.value;28 if (!sort) return data;2930 const accessor = sort.key.accessor as string;31 const dir = sort.direction === "asc" ? 1 : -1;3233 return data.sort((a, b) => {34 const aVal = a[accessor];35 const bVal = b[accessor];36 if (aVal == null && bVal == null) return 0;37 if (aVal == null) return dir;38 if (bVal == null) return -dir;39 if (typeof aVal === "string" && typeof bVal === "string") return dir * aVal.localeCompare(bVal);40 return dir * (Number(aVal) - Number(bVal));41 });42});4344function handleSortChange(sort: SortColumn | null) {45 sortConfig.value = sort;46}47</script>
1import { Component, Input } from "@angular/core";2import {SimpleTableComponent, asRows} from "@simple-table/angular";import type { AngularHeaderObject, Row, SortColumn, Theme } from "@simple-table/angular";3import { externalSortConfig } from "./external-sort.demo-data";4import "@simple-table/angular/styles.css";56@Component({7 selector: "external-sort-demo",8 standalone: true,9 imports: [SimpleTableComponent],10 template: `11 <simple-table12 [rows]="sortedRows"13 [defaultHeaders]="headers"14 [height]="height"15 [theme]="theme"16 [externalSortHandling]="true"17 [columnResizing]="true"18 [onSortChange]="handleSortChange"19 ></simple-table>20 `,21})22export class ExternalSortDemoComponent {23 @Input() height: string | number = "400px";24 @Input() theme?: Theme;2526 readonly headers: AngularHeaderObject[] = externalSortConfig.headers;27 private sortState: SortColumn | null = null;2829 handleSortChange = (sort: SortColumn | null): void => {30 this.sortState = sort;31 };3233 get sortedRows(): Row[] {34 const rows = [...asRows(externalSortConfig.rows)];35 if (!this.sortState) return rows;36 const accessor = this.sortState.key.accessor as string;37 const type = this.sortState.key.type;38 const dir = this.sortState.direction;39 return rows.sort((a, b) => {40 const aVal = a[accessor];41 const bVal = b[accessor];42 if (aVal === bVal) return 0;43 const cmp = type === "number"44 ? (aVal as number) - (bVal as number)45 : String(aVal).localeCompare(String(bVal));46 return dir === "asc" ? cmp : -cmp;47 });48 }49}505152// external-sort.demo-data.ts53// Self-contained demo table setup for this example.54import type { AngularHeaderObject } from "@simple-table/angular";555657export const externalSortData = [58 { id: 1, name: "Dr. Elena Vasquez", age: 42, email: "elena.vasquez@techcorp.com", salary: 145000, department: "AI Research" },59 { id: 2, name: "Kai Tanaka", age: 29, email: "k.tanaka@techcorp.com", salary: 95000, department: "UX Design" },60 { id: 3, name: "Amara Okafor", age: 35, email: "amara.okafor@techcorp.com", salary: 125000, department: "DevOps" },61 { id: 4, name: "Santiago Rodriguez", age: 27, email: "s.rodriguez@techcorp.com", salary: 82000, department: "Marketing" },62 { id: 5, name: "Priya Chakraborty", age: 33, email: "priya.c@techcorp.com", salary: 118000, department: "Engineering" },63 { id: 6, name: "Magnus Eriksson", age: 38, email: "magnus.erik@techcorp.com", salary: 110000, department: "Product" },64 { id: 7, name: "Zara Al-Rashid", age: 31, email: "zara.alrashid@techcorp.com", salary: 98000, department: "Sales" },65 { id: 8, name: "Luca Rossi", age: 26, email: "luca.rossi@techcorp.com", salary: 75000, department: "Marketing" },66 { id: 9, name: "Dr. Sarah Kim", age: 45, email: "sarah.kim@techcorp.com", salary: 165000, department: "AI Research" },67 { id: 10, name: "Olumide Adebayo", age: 30, email: "olumide.a@techcorp.com", salary: 105000, department: "Engineering" },68 { id: 11, name: "Isabella Chen", age: 24, email: "isabella.chen@techcorp.com", salary: 68000, department: "UX Design" },69 { id: 12, name: "Dmitri Volkov", age: 39, email: "dmitri.volkov@techcorp.com", salary: 135000, department: "DevOps" },70];7172export const externalSortHeaders: AngularHeaderObject[] = [73 { accessor: "name", label: "Name", width: "1fr", minWidth: 120, isSortable: true, type: "string" },74 { accessor: "age", label: "Age", width: 120, isSortable: true, type: "number" },75 { accessor: "department", label: "Department", width: 150, isSortable: true, type: "string" },76 { accessor: "email", label: "Email", width: 200, isSortable: true, type: "string" },77 {78 accessor: "salary",79 label: "Salary",80 width: 120,81 isSortable: true,82 type: "number",83 align: "right",84 valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`,85 },86];8788export const externalSortConfig = {89 headers: externalSortHeaders,90 rows: externalSortData,91 tableProps: { externalSortHandling: true, columnResizing: true },92} as const;93
1<script lang="ts">2 import {SimpleTable} from "@simple-table/svelte"; import type { Theme, SortColumn } from "@simple-table/svelte";3 import { externalSortConfig } from "./external-sort.demo-data";4 import "@simple-table/svelte/styles.css";56 let { height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();78 let sortConfig = $state<SortColumn | null>(null);910 let sortedRows = $derived.by(() => {11 const data = [...externalSortConfig.rows];12 if (!sortConfig) return data;1314 const accessor = sortConfig.key.accessor as string;15 const dir = sortConfig.direction === "asc" ? 1 : -1;1617 return data.sort((a, b) => {18 const aVal = a[accessor];19 const bVal = b[accessor];20 if (aVal == null && bVal == null) return 0;21 if (aVal == null) return dir;22 if (bVal == null) return -dir;23 if (typeof aVal === "string" && typeof bVal === "string") return dir * aVal.localeCompare(bVal);24 return dir * (Number(aVal) - Number(bVal));25 });26 });2728 function handleSortChange(sort: SortColumn | null) {29 sortConfig = sort;30 }31</script>3233<SimpleTable34 defaultHeaders={externalSortConfig.headers}35 rows={sortedRows}36 externalSortHandling={true}37 columnResizing={externalSortConfig.tableProps.columnResizing}38 onSortChange={handleSortChange}39 {height}40 {theme}41/>
1import {SimpleTable, asRows} from "@simple-table/solid";import type { Theme, SortColumn, Row } from "@simple-table/solid";2import { externalSortConfig } from "./external-sort.demo-data";3import { createSignal, createMemo } from "solid-js";4import "@simple-table/solid/styles.css";56export default function ExternalSortDemo(props: {7 height?: string | number;8 theme?: Theme;9}) {10 const [sortState, setSortState] = createSignal<SortColumn | null>(null);1112 const sortedRows = createMemo((): Row[] => {13 const sort = sortState();14 const rows = [...asRows(externalSortConfig.rows)];15 if (!sort) return rows;16 const accessor = sort.key.accessor as string;17 const type = sort.key.type;18 const dir = sort.direction;19 return rows.sort((a, b) => {20 const aVal = a[accessor];21 const bVal = b[accessor];22 if (aVal === bVal) return 0;23 const cmp =24 type === "number"25 ? (Number(aVal) || 0) - (Number(bVal) || 0)26 : String(aVal).localeCompare(String(bVal));27 return dir === "asc" ? cmp : -cmp;28 });29 });3031 return (32 <SimpleTable33 defaultHeaders={externalSortConfig.headers}34 rows={sortedRows()}35 height={props.height ?? "400px"}36 theme={props.theme}37 externalSortHandling={true}38 columnResizing={true}39 onSortChange={(sort) => setSortState(sort)}40 />41 );42}
1import { SimpleTableVanilla, asRows } from "simple-table-core";2import type { Theme, SortColumn, Row } from "simple-table-core";3import { externalSortConfig } from "./external-sort.demo-data";4import "simple-table-core/styles.css";56export function renderExternalSortDemo(7 container: HTMLElement,8 options?: { height?: string | number; theme?: Theme }9): SimpleTableVanilla {10 let currentSort: SortColumn | null = null;1112 function getSortedRows(): Row[] {13 const rows = [...asRows(externalSortConfig.rows)];14 if (!currentSort) return rows;15 const accessor = currentSort.key.accessor as string;16 const type = currentSort.key.type;17 const dir = currentSort.direction;18 return rows.sort((a, b) => {19 const aVal = a[accessor];20 const bVal = b[accessor];21 if (aVal === bVal) return 0;22 const cmp =23 type === "number"24 ? (Number(aVal) || 0) - (Number(bVal) || 0)25 : String(aVal).localeCompare(String(bVal));26 return dir === "asc" ? cmp : -cmp;27 });28 }2930 const table = new SimpleTableVanilla(container, {31 defaultHeaders: externalSortConfig.headers,32 rows: asRows(externalSortConfig.rows),33 height: options?.height ?? "400px",34 theme: options?.theme,35 externalSortHandling: true,36 columnResizing: true,37 onSortChange: (sort) => {38 currentSort = sort;39 table.update({ rows: getSortedRows() });40 },41 });42 return table;43}444546// external-sort.demo-data.ts47// Self-contained demo table setup for this example.48import type { HeaderObject } from "simple-table-core";495051export const externalSortData = [52 { id: 1, name: "Dr. Elena Vasquez", age: 42, email: "elena.vasquez@techcorp.com", salary: 145000, department: "AI Research" },53 { id: 2, name: "Kai Tanaka", age: 29, email: "k.tanaka@techcorp.com", salary: 95000, department: "UX Design" },54 { id: 3, name: "Amara Okafor", age: 35, email: "amara.okafor@techcorp.com", salary: 125000, department: "DevOps" },55 { id: 4, name: "Santiago Rodriguez", age: 27, email: "s.rodriguez@techcorp.com", salary: 82000, department: "Marketing" },56 { id: 5, name: "Priya Chakraborty", age: 33, email: "priya.c@techcorp.com", salary: 118000, department: "Engineering" },57 { id: 6, name: "Magnus Eriksson", age: 38, email: "magnus.erik@techcorp.com", salary: 110000, department: "Product" },58 { id: 7, name: "Zara Al-Rashid", age: 31, email: "zara.alrashid@techcorp.com", salary: 98000, department: "Sales" },59 { id: 8, name: "Luca Rossi", age: 26, email: "luca.rossi@techcorp.com", salary: 75000, department: "Marketing" },60 { id: 9, name: "Dr. Sarah Kim", age: 45, email: "sarah.kim@techcorp.com", salary: 165000, department: "AI Research" },61 { id: 10, name: "Olumide Adebayo", age: 30, email: "olumide.a@techcorp.com", salary: 105000, department: "Engineering" },62 { id: 11, name: "Isabella Chen", age: 24, email: "isabella.chen@techcorp.com", salary: 68000, department: "UX Design" },63 { id: 12, name: "Dmitri Volkov", age: 39, email: "dmitri.volkov@techcorp.com", salary: 135000, department: "DevOps" },64];6566export const externalSortHeaders: HeaderObject[] = [67 { accessor: "name", label: "Name", width: "1fr", minWidth: 120, isSortable: true, type: "string" },68 { accessor: "age", label: "Age", width: 120, isSortable: true, type: "number" },69 { accessor: "department", label: "Department", width: 150, isSortable: true, type: "string" },70 { accessor: "email", label: "Email", width: 200, isSortable: true, type: "string" },71 {72 accessor: "salary",73 label: "Salary",74 width: 120,75 isSortable: true,76 type: "number",77 align: "right",78 valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`,79 },80];8182export const externalSortConfig = {83 headers: externalSortHeaders,84 rows: externalSortData,85 tableProps: { externalSortHandling: true, columnResizing: true },86} as const;87
External sorting provides two key benefits:
- API Integration: Use
onSortChangeto trigger server-side sorting while keeping the table's UI sorting indicators. - Complete Control: Use
externalSortHandling=to disable all internal sorting and provide your own pre-sorted data.
External Sorting Configuration
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
initialSortColumnstring | Optional | Sets the column to sort by on initial table load. Provide the accessor of the column you want to sort by default. Supports simple accessors, nested paths (dot notation), and array indices (v1.9.4+). | |
initialSortDirection"asc" | "desc" | Optional | Sets the sort direction for the initial sort. Defaults to 'asc' if not specified. | |
onSortChange | Optional | Callback function triggered when sort configuration changes. Receives the current sort configuration or null if no sorting is applied. | |
externalSortHandlingboolean | Optional | When true, completely disables internal sorting logic. The table will not sort data internally - you must provide pre-sorted data via the rows prop. |