All bugs
mediumRender & network forensics

React Aria labels re-render 18× per store update and change nothing

The component is a minified, anonymous <code>ForwardRef(t)</code>. You'd never find it by name.

Reminders · CircleCIFound 2026-09-11Full report in Replay QA

What the recording showed

The commit at T=9.3s blocked for 66.2ms with 143 fibers, 124 of them wasted. ForwardRef(t) at 0fea-ihv~kq4d.js:657 re-rendered 18 of 19 instances. The same pattern repeats at T=9.8s.

Actual

The paragraph renders at rgb(154, 155, 163) on an effective backdrop of rgb(251, 251, 252), a contrast ratio of 2.67:1 — below the 4.5:1 WCAG AA minimum — so the text appears as faint gray that is hard to read on the white empty-state card.

Expected

The helper paragraph text should have a contrast ratio of at least 4.5:1 against the white empty-state card background (WCAG AA for 13px normal text), e.g. by using a darker gray token like the heading's #4a4b53 or another ≥4.5:1 muted color.

Session replay

Chronology of events

1
The app at 0:26.90:26.9
0:26.9

On the Reminders "Today" view with the search term "haircut" yielding 0 reminders, the empty-state card ("Nothing here yet") is displayed and its helper line "Try a different search or clear the filter." renders as faint gray text on the near-white card — measured contrast 2.67:1 (foreground rgb(154, 155, 163) on effective backdrop rgb(251, 251, 252) from the painted-below div.rounded-2xl), below the 4.5:1 WCAG AA minimum.

Root cause

The reminders empty-state component hardcodes the helper paragraph's text color as text-[#9a9ba3] (rgb(154, 155, 163)) at 13px (source: reminders empty-state JSX, class "mx-auto mt-2 max-w-xs text-[13px] leading-5 text-[#9a9ba3]"). Against the card's near-white effective backdrop rgb(251, 251, 252) (the div.rounded-2xl painted beneath the transparent-background paragraph), rgb(154, 155, 163) has a relative-luminance contrast ratio of 2.67:1 — below the 4.5:1 WCAG AA minimum for normal-size text. The token itself is simply too light for body-size text on this surface; the adjacent heading uses #4a4b53 and passes.

3 evidence probes (SearchSources, ReadSource, Evaluate)
SearchSources {"pattern":"Try a different search or clear the filter"}
→ ### http://127.0.0.1:3000/_next/static/chunks/0fea-ihv~kq4d.js
 hits | L | code 
------|------|------
     |   46 | }, 21800, e => { 

     | 7327 |                     children: o 
     | *7328 |                               ? "Try a different search or clear the filter." 
     | 7329 |                               : "A quiet list is a good place to start."
ReadSource {"line":7326,"path":"http://127.0.0.1:3000/_next/static/chunks/0fea-ihv~kq4d.js"}
→  hits | L | code 
------|------|------
     | 7301 |              children: [ 
     | 7302 |                (0, 
   0 | 7303 |                 c.jsx)( 
     | 7304 |                   "span", 
     | 7305 |                   { 
     | 7306 |                     className: "mx-auto mb-4 grid size-12 place-items-center rounded-2xl bg-[#f0f0f4] text-[#a4a5ad]", 
     | 7307 |                     children: (0, 
   0 | 7308 |                                c.jsx)( 
     | 7309 |                                  C, 
     | 7310 |                                  { className: "size-6", "aria-hidden": "true" } 
     | 7311 |                                ) 
     | 7312 |                   } 
     | 7313 |                 ), 
     | 7314 |                (0, 
   0 | 7315 |                 c.jsx)( 
     | 7316 |                   "h2", 
     | 7317 |                   { 
     | 7318 |                     className: "text-[15px] font-semibold text-[#4a4b53]", 
     | 7319 |                     children: "Nothing here yet" 
     | 7320 |                   } 
     | 7321 |                 ), 
     | 7322 |                (0, 
   0 | 7323 |                 c.jsx)( 
     | 7324 |                   "p", 
     | 7325 |                   { 
     | *7326 |                     className: "mx-auto mt-2 max-w-xs text-[13px] leading-5 text-[#9a9ba3]", 
     | 7327 |                     children: o 
     | 7328 |                               ? "Try a different search or clear the filter." 
     | …
Evaluate {"point":"Point:49","scope":"global","expression":"(() => { try { var el = document.querySelector(\"div.min-h-0.flex-1 > div.mx-auto.w-full > div.rounded-2xl.border:nth-of-type(2) > p.mx-auto.mt-2\"); if (!el) return JSON.stringify({ found: false, selector: \"div.min-h-0.flex-1 > div.mx-auto.w-full > div.rounded-2xl.border:nth-of-type(2) > p.mx-auto.mt-2\" }); var r = el.getBoundingClientRect(); var cs = getComputedStyle(el); var parseC = function (s) { if (!s || s === 'transparent') return null; var i = s.indexOf('('), j = s.indexOf(')'); if (i < 0 || j < 0) return null; var p = s.slice(i + 1…
→ "{\"found\":true,\"tag\":\"p\",\"text\":\"Try a different search or clear the filter.\",\"rect\":{\"x\":623,\"y\":467,\"w\":320,\"h\":20},\"viewport\":{\"w\":1280,\"h\":720},\"textColor\":\"rgb(154, 155, 163)\",\"ownBackgroundColor\":\"rgba(0, 0, 0, 0)\",\"effectiveBackdrop\":\"rgb(251, 251, 252)\",\"effectiveBackdropSource\":\"div.rounded-2xl\",\"effectiveBackdropDefaulted\":false,\"contrastRatio\":2.67,\"invisible\":false,\"fontSize\":\"13px\",\"fontWeight\":\"400\"}"

Root cause → actual behavior

1

The reminders empty-state component assigns the hardcoded token text-[#9a9ba3] (rgb(154, 155, 163)) to the helper paragraph "Try a different search or clear the filter." — confirmed in the bundle source where the paragraph is created with class "mx-auto mt-2 max-w-xs text-[13px] leading-5 text-[#9a9ba3]".

2 evidence probes (SearchSources, ReadSource)
SearchSources {"pattern":"Try a different search or clear the filter"}
→ ### http://127.0.0.1:3000/_next/static/chunks/0fea-ihv~kq4d.js
 hits | L | code 
------|------|------
     |   46 | }, 21800, e => { 

     | 7327 |                     children: o 
     | *7328 |                               ? "Try a different search or clear the filter." 
     | 7329 |                               : "A quiet list is a good place to start."
ReadSource {"line":7326,"path":"http://127.0.0.1:3000/_next/static/chunks/0fea-ihv~kq4d.js"}
→  hits | L | code 
------|------|------
     | 7301 |              children: [ 
     | 7302 |                (0, 
   0 | 7303 |                 c.jsx)( 
     | 7304 |                   "span", 
     | 7305 |                   { 
     | 7306 |                     className: "mx-auto mb-4 grid size-12 place-items-center rounded-2xl bg-[#f0f0f4] text-[#a4a5ad]", 
     | 7307 |                     children: (0, 
   0 | 7308 |                                c.jsx)( 
     | 7309 |                                  C, 
     | 7310 |                                  { className: "size-6", "aria-hidden": "true" } 
     | 7311 |                                ) 
     | 7312 |                   } 
     | 7313 |                 ), 
     | 7314 |                (0, 
   0 | 7315 |                 c.jsx)( 
     | 7316 |                   "h2", 
     | 7317 |                   { 
     | 7318 |                     className: "text-[15px] font-semibold text-[#4a4b53]", 
     | 7319 |                     children: "Nothing here yet" 
     | 7320 |                   } 
     | 7321 |                 ), 
     | 7322 |                (0, 
   0 | 7323 |                 c.jsx)( 
     | 7324 |                   "p", 
     | 7325 |                   { 
     | *7326 |                     className: "mx-auto mt-2 max-w-xs text-[13px] leading-5 text-[#9a9ba3]", 
     | 7327 |                     children: o 
     | 7328 |                               ? "Try a different search or clear the filter." 
     | …
2

The paragraph's own background is transparent, so the browser paints the text over the near-white div.rounded-2xl card surface beneath it — the resolved effective backdrop is rgb(251, 251, 252) (measured via ancestor background walk at Point:49).

3

rgb(154, 155, 163) on rgb(251, 251, 252) computes to a 2.67:1 contrast ratio (measured), below the 4.5:1 WCAG AA minimum for 13px normal text, so the user sees the empty-state helper line as faint gray that is difficult to read on the white card.

Is your app hiding bugs like this?

Replay QA explores every build, records what it finds, and writes the root cause.