Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to make tables sortable in React

Sortable tables enhance user experience by enabling dynamic data organization, especially crucial for dashboards and data-heavy applications. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented sortable tables in countless enterprise React applications throughout my 11 years of frontend development. The most effective approach is managing sort state with useState and applying sort logic to reorder table data. This method provides responsive sorting with clear visual feedback and maintains clean component structure.

Manage sort column and direction in state, apply sorting logic to data array, and toggle sort on header clicks.

import { useState } from 'react'

const SortableTable = ({ data }) => {
  const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' })

  const sortedData = [...data].sort((a, b) => {
    if (!sortConfig.key) return 0

    const aValue = a[sortConfig.key]
    const bValue = b[sortConfig.key]

    if (aValue < bValue) return sortConfig.direction === 'asc' ? -1 : 1
    if (aValue > bValue) return sortConfig.direction === 'asc' ? 1 : -1
    return 0
  })

  const handleSort = (key) => {
    setSortConfig({
      key,
      direction: sortConfig.key === key && sortConfig.direction === 'asc' ? 'desc' : 'asc'
    })
  }

  return (
    <table>
      <thead>
        <tr>
          <th onClick={() => handleSort('name')}>
            Name {sortConfig.key === 'name' && (sortConfig.direction === 'asc' ? '↑' : '↓')}
          </th>
          <th onClick={() => handleSort('email')}>
            Email {sortConfig.key === 'email' && (sortConfig.direction === 'asc' ? '↑' : '↓')}
          </th>
          <th onClick={() => handleSort('role')}>
            Role {sortConfig.key === 'role' && (sortConfig.direction === 'asc' ? '↑' : '↓')}
          </th>
        </tr>
      </thead>
      <tbody>
        {sortedData.map(user => (
          <tr key={user.id}>
            <td>{user.name}</td>
            <td>{user.email}</td>
            <td>{user.role}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

Here the sortConfig state tracks the currently sorted column key and direction. The sortedData creates a copy of the data array and sorts it based on the active column and direction. The handleSort function toggles between ascending and descending when clicking the same column, or resets to ascending for new columns. Arrow indicators (↑ ↓) provide visual feedback showing which column is sorted and in what direction. The sort comparison handles both string and numeric values correctly.

Best Practice Note:

This is the sorting approach we use in CoreUI table components for reliable data organization in enterprise dashboards. Use useMemo to optimize sorting performance for large datasets, implement multi-column sorting by tracking an array of sort configs, and consider case-insensitive sorting for string columns with toLowerCase() to improve user experience.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
The Best Bootstrap Alternative for Developers in 2025
The Best Bootstrap Alternative for Developers in 2025

How to conditionally add attributes to React components
How to conditionally add attributes to React components

How to loop inside React JSX
How to loop inside React JSX

Open Source vs Commercial Admin Templates: Which Should You Choose in 2026?
Open Source vs Commercial Admin Templates: Which Should You Choose in 2026?

Answers by CoreUI Core Team