All questions

Data Table V

Premium

Data Table V

Build an accessible data table over 24 fixed { id, name, role, score } rows. Sorting, pagination, and selection must cooperate without turning the visible eight rows into a second source of truth.

What you'll build

The polished starter renders the complete resting view, but its controls are intentionally inert. Add React state, derivations, event handlers, and the live accessibility state.

  1. Sort. Clicking 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.
  2. Paginate. Page size is 8, so there are 3 pages. The footer has Prev / page numbers / Next and a Page X of 3 readout. Prev is disabled on page 1, Next on the last page.
  3. Select. A checkbox per row toggles that row's id in a Set. The header checkbox selects or deselects every row on the current page. It is checked when all eight are selected and indeterminate when only some are selected. A N selected readout shows selected.size, and selected ids persist as you page.
  4. Make it accessible. Put real buttons inside sortable <th> cells, expose aria-sort on each sortable header, label every checkbox, mark the current page with aria-current="page", and announce the selection and page readouts with aria-live="polite".

Behavior contract

  • Initial state is the original row order, page 1, ascending direction prepared for the first sort, and no selection.
  • A new sortable column starts ascending; activating the current column flips its direction. Every sort returns to page 1.
  • Sort all 24 rows before slicing eight rows for the current page. Previous and next clamp to pages 1–3.
  • Row selection is keyed by id and survives sorting and pagination. Select-all changes only the eight visible ids.
  • The visible arrow, aria-sort, checked/indeterminate header checkbox, selected-row treatment, live readouts, disabled boundaries, and aria-current must always match state.

Examples

  • Click 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.
  • On page 1 tick the header checkbox: all 8 visible rows get selected and 8 selected shows. Go to page 2 — its rows are unticked, but page 1's selection is remembered when you return.

Notes

  • Derive, don't store. The visible rows are sort(ROWS) → slice(page) computed during render, not a second piece of state you keep in sync.
  • Selection is independent. Keep it in a Set<number> of ids so it survives sorting and paging; don't tie it to row positions.
  • Select-all is page-scoped. The header checkbox only touches the ids currently on screen, not all 24.
  • React detail. Replace the Set rather than mutating it, and synchronize the checkbox's DOM-only indeterminate property with a ref and effect.
  • Styling is already in styles.css and remains in place when the solution replaces App.tsx.
WE’RE LISTENING

Help make UIReady better

Found a bug or have an idea? Tell us about it.

Up to 3 files · 5 MiB each · JPG, PNG, WebP, MP4, WebM, MP3, M4A or WAV