Build a data table over a fixed set of 24 rows — { id, name, role, score } — that does three things every real table does: sort by a column, paginate in pages of 8, and select rows with checkboxes. The trick is keeping these three concerns from stepping on each other: the sorted-then-sliced view is one derivation, and the selection is a separate Set of ids that outlives paging.
The starter App.tsx renders page 1 in the default order with dead controls. Make it interactive:
Name, Role, or Score sorts ascending; clicking the same header again toggles descending. A ▲/▼ arrow marks the active column. Sorting jumps back to page 1.Prev / page numbers / Next and a Page X of 3 readout. Prev is disabled on page 1, Next on the last page.Set. The header checkbox selects or deselects every row on the current page. A N selected readout shows selected.size, and selected ids persist as you page.Score once: rows reorder low-to-high with a ▲ on Score. Click Score again: high-to-low with a ▼. Click Name: back to ▲, now on Name, and you snap to page 1.8 selected shows. Go to page 2 — its rows are unticked, but page 1's selection is remembered when you return.sort(ROWS) → slice(page) computed during render, not a second piece of state you keep in sync.Set<number> of ids so it survives sorting and paging; don't tie it to row positions.styles.css; focus on the state and derivations.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.