React dashboard design patterns that hold up
Composition, URL state and server boundaries — the patterns that stay pleasant past ten screens.
UT Studio7 min read
Dashboard code decays in predictable ways. Three patterns prevent most of it, and none of them require a library.
Compose, do not configure
The instinct with a repeated component is to add props. Twelve screens later the table takes thirty of them and every change risks all twelve.
// Configuration: every new need is another prop.
<DataTable rows={rows} showFilters showExport onExport={…} dense stickyHeader />
// Composition: every new need is another child.
<Table>
<Table.Toolbar><Filters /><ExportButton /></Table.Toolbar>
<Table.Body rows={rows} />
<Table.Pagination />
</Table>Put view state in the URL
Filters, sort, page and the selected tab belong in the query string — not in component state, and not in a store.
- The view is shareable, which is most of what internal tools are used for.
- Back works, and refresh does not reset the screen.
- It can be read on the server, so the first paint is already correct.
- You delete a state management dependency.
Keep client boundaries at the leaves
A table is not interactive. Its sort control is. Marking the whole table as a client component to make one header clickable ships every row to the browser as JavaScript.
Pass data down, not imports across
A client island should take what it needs as props. Importing the data module from inside a client component drags the module — and everything it imports — into the bundle.
One loading strategy per screen
Mixing route-level loading, per-component spinners and skeletons on one screen produces a page that flashes three times. Pick one per screen and hold it.
Patterns worth avoiding
| Pattern | Problem |
|---|---|
| Global store for server data | Two sources of truth, and cache invalidation you now own |
| Prop-drilling through five levels | A composition problem wearing a state costume |
| useEffect for data fetching | Waterfalls, and a loading state that could have been server-rendered |
| Context for anything that changes often | Re-renders every consumer |
Templates built this way
Templates mentioned here
Everything above is written against real products. These are the ones this page draws on.
