Analytics Dashboard
A data-heavy interface that stays fast and accessible: filters, charts, large tables and honest loading states.
Technologies
The brief
What the finished thing needs to do.
- Several visualisations driven by a shared set of filters
- A table of thousands of rows that remains responsive
- Date range, category and search filters that combine
- Filter state reflected in the URL so a view can be shared
- Genuine loading, empty and error states for every data area
- Accessible charts, including a non-visual way to get the same information
- Usable on a tablet
How to structure it
Filter state belongs in the URL rather than in component state. That makes views shareable and the back button work, and it removes the need to synchronise two sources of truth.
Each data area manages its own loading and error state. One global spinner blocking the whole page is worse for the user than sections resolving independently.
Large tables need virtualisation: render only the visible rows. Rendering ten thousand rows will make the page unusable regardless of how fast the data arrives.
Accessible charts are the requirement people skip. A chart is an image to a screen reader, so the same information must be available another way — a data table, or a clear text summary.
Why these technologies
- URL as filter state
- Shareable views and working browser navigation, with one source of truth.
- Row virtualisation
- Keeps a large table responsive by rendering only what is visible.
- Per-section data states
- Sections resolve independently instead of blocking the entire page.
- Accessible chart alternatives
- Visualisations are inaccessible by default; the data must be reachable another way.
Build it in this order
Each stage produces something that works. That matters — a project that only runs at the very end is a project people abandon.
Layout with fixed data
Get the structure and responsive behaviour right before adding real data.
One chart from real data
Including its loading and error states.
Filters in the URL
Read from and write to query parameters.
Connect filters to data
Changing a filter refetches; concurrent responses must not arrive out of order.
The large table
Add virtualisation and confirm scrolling stays smooth.
Remaining visualisations
All driven by the same filter state.
Accessibility pass
Keyboard operation throughout, and non-visual access to every chart's data.
Performance pass
Measure, then remove unnecessary rendering and reduce bundle weight.
Done means
How to know it is finished
Check each of these before moving on. If one fails, the project is not done yet — and that is useful information rather than a setback.
- A filtered view can be shared by URL and loads identically
- Browser back and forward move through filter states correctly
- The large table scrolls smoothly with thousands of rows
- Every data area shows appropriate loading, empty and error states
- All chart information is available without relying on sight
- The whole dashboard is operable by keyboard
If you want to go further
Extensions worth attempting
Only once the core build meets every criterion above.
- Add CSV export of the current filtered view
- Add saved filter presets
- Add live updates and handle them without disrupting scroll position
- Add comparison against a previous period
Other projects at this level
Document Management Platform
An architecture exercise: file storage, versioning, permissions and background processing, structured to stay maintainable.
AI Knowledge Assistant
The flagship AI project: a full assistant with retrieval, tool use, conversation, guardrails, evaluation and cost tracking.
Have a project worth talking through?
Tell us what you're building or what's slowing your current system down. We'll give you a direct read on scope and approach.