Skip to main content
ANVISoftware Solutions

Analytics Dashboard

Advanced25-35 hours

A data-heavy interface that stays fast and accessible: filters, charts, large tables and honest loading states.

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.

  1. Layout with fixed data

    Get the structure and responsive behaviour right before adding real data.

  2. One chart from real data

    Including its loading and error states.

  3. Filters in the URL

    Read from and write to query parameters.

  4. Connect filters to data

    Changing a filter refetches; concurrent responses must not arrive out of order.

  5. The large table

    Add virtualisation and confirm scrolling stays smooth.

  6. Remaining visualisations

    All driven by the same filter state.

  7. Accessibility pass

    Keyboard operation throughout, and non-visual access to every chart's data.

  8. 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

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.