Blog: Fixing Inconsistent Page Headers Across the Dashboard
Fixing Inconsistent Page Headers Across the Dashboard
Release v0.1.79 · UI/UX · Consistency
The Problem
As the dashboard has grown, individual page components accumulated their own heading elements independently of the shared layout. This led to two distinct and opposite problems living side-by-side in the same application:
| Page | Symptom |
|---|---|
| Deposit Release Dashboard | Title appeared twice — once in the header bar, once as an <h1> in the page body |
| Deduction Claim Builder | Title appeared twice — same root cause |
| Tenancy Timeline View | Title appeared twice — same root cause |
| Compliance Dashboard | Title appeared once (header bar only) — no in-body heading at all |
For users this meant visual inconsistency jumping between sections. For screen-reader and assistive-technology users it was worse: multiple <h1> elements on a single page breaks document outline semantics, and pages with no <h1> outside the nav region can confuse landmark navigation.
The Root Cause
The dashboard shell already renders a DashboardHeaderTitle component in the top header bar for every page. This is wired to breadcrumb/routing context and is always present. There was no documented convention, however, about whether individual page components should also render a heading — so each page made its own call.
What We Changed
One rule, applied everywhere
DashboardHeaderTitlein the layout header is the page title for every dashboard page. Page components do not render their own<h1>.
Duplicate <h1> tags have been removed from DepositReleaseDashboard, the Deduction Claim Builder, and TenancyTimelineView.
What about pages that need more context?
Some pages genuinely benefit from a short description or sub-heading beneath the header — a one-liner explaining what the current view is for, or surfacing a key status at a glance. For those cases we have introduced a standardised <PageHeader> component:
// Use when a contextual description adds value below the header bar.
// Do NOT pass the page title here — it is already in DashboardHeaderTitle.
<PageHeader
description="Review and approve pending deposit release requests."
/>
<PageHeader> renders a <p> (not an <h1>), keeping the document outline clean while still allowing contextual text in the content area.
Before / After
Before — Deposit Release Dashboard
[Header bar] Deposit Releases ← DashboardHeaderTitle
──────────────────────────────────────
Deposit Releases ← <h1> in page body (duplicate)
┌─────────────────────────────────┐
│ ...table content... │
└─────────────────────────────────┘
After — Deposit Release Dashboard
[Header bar] Deposit Releases ← DashboardHeaderTitle (single source of truth)
──────────────────────────────────────
┌─────────────────────────────────┐
│ ...table content... │
└─────────────────────────────────┘
Impact
- Visual — Cleaner content area; no repeated title consuming vertical space.
- Accessibility — Each page now has exactly one
<h1>(insideDashboardHeaderTitle), producing a valid document outline. - Consistency — Developers adding new pages have a clear, documented pattern to follow.
- No breaking changes — No API, data model, or URL changes. Existing users will notice only the visual improvement.
Guidance for Custom Pages
If you maintain custom dashboard pages:
- Remove any
<h1>from your page component ifDashboardHeaderTitlealready shows the page title. - Do not pass the page title into
<PageHeader>— it accepts onlydescription. - Use
<PageHeader description="…" />only when a short contextual description genuinely helps users orient themselves on that page.