React - Data Table Sorting & Filtering

Overview

Estimated time: 20–30 minutes

Create a small data table with column sorting, text filtering, and accessible sort indicators.

Try it: Sort and filter

View source
function DataTable(){
  const rows = React.useMemo(()=>[
    {id:1, name:'Alice', role:'Admin'},
    {id:2, name:'Bob', role:'User'},
    {id:3, name:'Carol', role:'User'},
    {id:4, name:'Dave', role:'Moderator'},
  ], []);
  const [q, setQ] = React.useState('');
  const [sort, setSort] = React.useState({key:'name', dir:'asc'});
  const filtered = rows.filter(r => (r.name+r.role).toLowerCase().includes(q.toLowerCase()));
  const sorted = [...filtered].sort((a,b)=>{
    const av = a[sort.key].toString().toLowerCase();
    const bv = b[sort.key].toString().toLowerCase();
    return sort.dir==='asc' ? av.localeCompare(bv) : bv.localeCompare(av);
  });
  function toggle(key){ setSort(s => ({ key, dir: s.key===key && s.dir==='asc' ? 'desc' : 'asc'})); }
  function Icon({k}){ return {sort.key===k ? (sort.dir==='asc'?' ▲':' ▼') : ''}; }
  return (
    <div>
      <label>Filter <input value={q} onChange={e => setQ(e.target.value)} /></label>
      <table role="table" style={{width:'100%', marginTop:8}}>
        <thead><tr>
          <th role="columnheader" scope="col"><button onClick={()=>toggle('name')} aria-sort={sort.key==='name'? sort.dir:'none'}>Name<Icon k="name" /></button></th>
          <th role="columnheader" scope="col"><button onClick={()=>toggle('role')} aria-sort={sort.key==='role'? sort.dir:'none'}>Role<Icon k="role" /></button></th>
        </tr></thead>
        <tbody>
          {sorted.map(r => <tr key={r.id}><td>{r.name}</td><td>{r.role}</td></tr>)}
        </tbody>
      </table>
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('try-table')).render(<DataTable />);

Syntax primer

  • aria-sort communicates the current sort order to assistive tech.
  • Use stable sort keys and avoid in-place mutation.

Common pitfalls

  • Sorting numbers as strings—normalize values before compare.

Exercises

  1. Add multi-column sort and a clear sort button.

Checks for Understanding

  1. What does aria-sort communicate, and where should it live?
  2. Why copy arrays before sorting/filtering instead of mutating?
Show answers
  1. The current sort direction for a column; apply it to the interactive column header.
  2. To keep state immutable so React can detect changes and avoid subtle bugs.