Build a sortable data table
Render a table of people with columns Name, Age and City. Clicking a column header sorts the rows by that column.
A header cycles through three states on repeated click: ascending → descending → none (original order). Only one column is sorted at a time — clicking a new header resets the previous one.
Requirements
- Each column header is a `<button data-testid="header-{name|age|city}">`.
- Each sortable header reflects state via `aria-sort="ascending"`, `"descending"` or `"none"`.
- Rows are `<tr data-testid="row">` elements rendering `.name`, `.age`, `.city` as plain text cells.
- First click sorts ascending; second click on the same header sorts descending; third click returns to the original order.
- Clicking a different header resets the previous header's `aria-sort` to `"none"` and starts fresh on the new column.
- Sorting must be stable — two rows with the same sort key preserve their original relative order.
Where it's been asked
- Microsoft
- Amazon
- Atlassian
- Stripe
From public interview reports — a build very like this one has shown up in a round at these companies. Not an exhaustive list.
Stuck? The react course covers the ideas this problem is built on.
import { useState } from "react"; const PEOPLE = [ { name: "Priya", age: 29, city: "Bengaluru" }, { name: "Omar", age: 34, city: "Dubai" }, { name: "Ana", age: 29, city: "Lisbon" }, { name: "Kenji", age: 41, city: "Tokyo" }, { name: "Zara", age: 29, city: "Karachi" }, ]; export default function App() { const [sort, setSort] = useState({ column: null, direction: "none" }); // TODO: derive sortedRows from PEOPLE based on sort.column + sort.direction. // Remember: stable sort, three-state cycle, only one active column. const sortedRows = PEOPLE; return ( <table style={{ fontFamily: "sans-serif", borderCollapse: "collapse", padding: 16 }}> <thead> <tr> {["name", "age", "city"].map((col) => ( <th key={col}> <button data-testid={`header-${col}`} aria-sort="none" style={{ padding: 8, cursor: "pointer" }} > {col.toUpperCase()} </button> </th> ))} </tr> </thead> <tbody> {sortedRows.map((person, i) => ( <tr key={i} data-testid="row"> <td style={{ padding: 8 }}>{person.name}</td> <td style={{ padding: 8 }}>{person.age}</td> <td style={{ padding: 8 }}>{person.city}</td> </tr> ))} </tbody> </table> ); }
Ready to check it?
5 tests run against your rendered component, right here in your browser. Sign in to claim the XP when you pass.
Need a nudge?
Reveal a conceptual hint or the reference solution. Both were written and reviewed with the problem — no runtime magic.
Discussion
Sign in to postNo comments yet. Be the first to say something.