openstatushq/openstatus
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 9, 2026
More findings
Verdict
Solid token discipline collapses at the edges: every loading, error, or empty state just renders blank instead of designed feedback. The biggest risk is users mistaking a legitimate empty or failed state for a broken app.
Files Rams reviewed
apps/dashboard/src/app/(dashboard)/status-pages/[id]/components/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/components/page.tsx
apps/web/src/app/(landing)/play/cdn-checker/components/monitor-cta.tsx
apps/web/src/app/(landing)/play/cdn-checker/components/results-table.tsx
apps/web/src/app/(landing)/play/cdn-checker/components/summary-card.tsx
apps/dashboard/src/app/(dashboard)/agents/page.tsx
apps/dashboard/src/app/(dashboard)/chat/layout.tsx
apps/dashboard/src/app/(dashboard)/cli/page.tsx
apps/dashboard/src/app/(dashboard)/layout.tsx
apps/dashboard/src/app/(dashboard)/monitors/[id]/incidents/layout.tsx
apps/dashboard/src/app/(dashboard)/monitors/[id]/incidents/page.tsx
apps/dashboard/src/app/(dashboard)/monitors/[id]/layout.tsx
apps/dashboard/src/app/(dashboard)/monitors/create/page.tsx
apps/dashboard/src/app/(dashboard)/overview/layout.tsx
apps/dashboard/src/app/(dashboard)/overview/page.tsx
apps/dashboard/src/app/(dashboard)/settings/(list)/page.tsx
apps/dashboard/src/app/(dashboard)/settings/account/page.tsx
apps/dashboard/src/app/(dashboard)/settings/general/layout.tsx
apps/dashboard/src/app/(dashboard)/settings/general/page.tsx
apps/dashboard/src/app/(dashboard)/settings/integrations/layout.tsx
apps/dashboard/src/app/(dashboard)/settings/integrations/page.tsx
apps/dashboard/src/app/(dashboard)/settings/private-locations/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/history/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/maintenances/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/maintenances/page.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/status-reports/[reportId]/page.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/status-reports/layout.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/status-reports/page.tsx
apps/dashboard/src/app/(dashboard)/status-pages/[id]/subscribers/page.tsx
Accessibility
"Monitor this URL" link opens a new tab with no warning to screen reader users
The `<a>` labeled "Monitor this URL" sets `target="_blank" rel="noreferrer"` but the accessible name is only the visible text, with no indication the link leaves the current tab.
Why it matters
Screen reader and keyboard users get no warning before losing their place in the flow to a new tab, which breaks the expected back-navigation and disorients anyone not watching the browser chrome.
Fix
Add visually-hidden text (or an aria-label suffix) announcing that the link opens in a new tab.
Monitor this URL
</a> Monitor this URL
<span className="sr-only"> (opens in a new tab)</span>
</a>Three table headers are empty, leaving icon and details columns unnamed
The header row has `<th className="w-12" />` three times for the provider icon, cache-status, and details columns, only "Region" and "Latency" carry visible header text.
Why it matters
Screen reader users navigating the table by column header hear nothing for three of the five columns, so the meaning of each icon and the details control is lost outside of visual context.
Fix
Give every header cell an accessible name, using visually-hidden text where a visual label isn't wanted.
<th className="w-12" />
<th className="w-12" />
<th>Region</th>
<th className="text-right!">Latency</th>
<th className="w-12" /><th className="w-12"><span className="sr-only">Provider</span></th>
<th className="w-12"><span className="sr-only">Cache status</span></th>
<th>Region</th>
<th className="text-right!">Latency</th>
<th className="w-12"><span className="sr-only">Details</span></th>Decorative Info icon in the paid-feature note is unlabeled noise for screen readers
The upgrade note renders `<Info />` directly beside the text "This is a paid feature. Upgrade your plan to use the Slack agent." with no `aria-hidden` on the icon.
Why it matters
Screen readers announce the icon as "image" or its raw SVG name right before reading the sentence, adding noise that duplicates the adjacent label and slows comprehension for assistive-tech users.
Fix
Mark purely decorative icons sitting next to their own text label as aria-hidden.
<Note color="info" size="sm">
<Info />
This is a paid feature. Upgrade your plan to use the Slack agent.
</Note><Note color="info" size="sm">
<Info aria-hidden="true" />
This is a paid feature. Upgrade your plan to use the Slack agent.
</Note>UX
Page goes completely blank while loading or on fetch failure
The component returns `null` whenever `statusPage` is falsy: `if (!statusPage) return null;`. This covers the initial loading state, a failed query, and a not-found id with the exact same blank screen.
Why it matters
Users clicking into a status page's components tab see nothing rendered, with no way to tell if the page is loading, failed to load, or doesn't exist. There's no feedback and no recovery path.
Fix
Render distinct loading and error states instead of a silent null return.
if (!statusPage) return null;const { data: statusPage, isLoading, error } = useQuery(
trpc.page.get.queryOptions({ id: Number.parseInt(id) }),
);
if (isLoading) return <SectionGroup><Section>Loading...</Section></SectionGroup>;
if (error || !statusPage) return <SectionGroup><Section>Couldn't load this page. <button onClick={() => location.reload()}>Try again</button></Section></SectionGroup>;Card vanishes entirely instead of showing a designed empty or loading state
`SummaryCard` returns `null` whenever `summary` is falsy: `if (!summary) return null;`. There's no skeleton, spinner, or placeholder message shown while a check is running or before one has been triggered.
Why it matters
Users see a gap where the card should be with no signal that anything is happening, which reads as a broken page rather than a pending state.
Fix
Render a designed placeholder (skeleton or waiting message) instead of returning null.
if (!summary) return null;if (!summary) {
return (
<div className="border-border text-muted-foreground grid gap-4 border p-4 text-sm sm:grid-cols-3">
Waiting for check results…
</div>
);
}Empty results row shows blank `<br />` cells with no message to the user
When `successRows.length === 0`, the table renders one `<tr>` whose last three cells contain only `<br />` tags, no text, no explanation of whether the check is running, failed, or returned nothing.
Why it matters
Users see an unlabeled row of icons next to blank space and have no way to tell if the tool is broken, still loading, or genuinely found no successful regions, which stalls their next action.
Fix
Replace the blank filler cells with a designed empty/loading state that names what happened and what to do next.
<tr>
<td>
<IconCloudProvider
provider="globe"
className="text-muted-foreground size-4"
/>
</td>
<td>
<div className="bg-muted-foreground size-4" />
</td>
<td>
<br />
</td>
<td>
<br />
</td>
<td>
<br />
</td>
</tr><tr>
<td colSpan={5} className="text-muted-foreground py-6 text-center text-sm">
No successful checks yet.
</td>
</tr>Typography
Color
Spacing
Components
Motion
Craft
Working well
- Status color comes from semantic tokens (`text-success`, `text-warning`, `text-destructive`, `border-border`) rather than hardcoded hex, and each colored value is still backed by the visible number or word itself ("18 / 20", "None") rather than color alone, so the state reads correctly even without color perception.
- Reusing shared `Section`, `SectionHeader`, `SectionTitle`, `SectionDescription`, and `Note` primitives instead of one-off divs keeps this page's spacing and typography consistent with the rest of the dashboard, and means a future token or spacing change propagates here for free instead of drifting.
- `CacheStatusLegend` renders the status name as visible text inside the colored swatch (`{status}` inside the colored div), which is exactly the right fallback: color plus a text label means colorblind users aren't locked out of the legend even though the row indicator itself skips this pattern.
- The page orders its two sections correctly: "Slack agent" (setup and install) comes before "Messages" (usage examples), so a new user hits the action they need before the reference material. That sequencing matches how someone actually approaches the feature: set it up, then learn what to say.
Score your own repo with Rams.
Free on public repos. Rams reviews every pull request for accessibility, color, type, spacing, components, motion, UX, and craft, and posts inline fixes.