You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Search results, source-detail chunk cards, and Timeline entries are rendered as bare <div> containers without semantic roles or accessible names. Keyboard / screen-reader users encounter them as anonymous regions. The only list-row in the app that exposes a button role is home-source-item on the Home tab.
Found by Playwright UX review of v0.1.34 prod (2026-05-02). See docs/reports/mm-web-prod-v0.1.34-playwright-review.md (P2 — Accessibility labels are weak for result/list items).
Evidence
Across packages/memtomem/src/memtomem/web/static/app.js and index.html:
The only role="button" applied to a list-row is on home-source-item (index.html:1310):
role="list" and role="listitem" are not used anywhere in the static surface.
Search results (.result-item), source detail chunk cards, and Timeline rows are constructed as plain <div> containers with no role, aria-label, or aria-labelledby.
Why this matters
Screen-reader users land on selectable rows that announce as "group" or generic landmarks instead of "button: :".
Keyboard users can't tell from the focus ring whether a row is interactive.
Browser automation (and future a11y tests) has to lean on brittle text matching instead of semantic queries.
Suggested fix (incremental — does not have to be one PR)
For each list surface, decide between two patterns:
role="list" + role="listitem" when the row is informational only. Add aria-label describing what each row contains (e.g. aria-label="${basename}, lines ${start}-${end}, ${namespace}").
role="button" + tabindex="0" when the entire row is clickable / activates an action. Match the existing home-source-item pattern.
Targets:
Search results list (#results-list .result-item)
Source detail chunk cards (find via grep for chunk card construction in app.js)
Timeline entries (Timeline tab list rows)
Generate accessible names from the same source/line/namespace data that's already on the row.
Summary
Search results, source-detail chunk cards, and Timeline entries are rendered as bare
<div>containers without semantic roles or accessible names. Keyboard / screen-reader users encounter them as anonymous regions. The only list-row in the app that exposes a button role ishome-source-itemon the Home tab.Found by Playwright UX review of v0.1.34 prod (2026-05-02). See
docs/reports/mm-web-prod-v0.1.34-playwright-review.md(P2 — Accessibility labels are weak for result/list items).Evidence
Across
packages/memtomem/src/memtomem/web/static/app.jsandindex.html:role="button"applied to a list-row is onhome-source-item(index.html:1310):role="list"androle="listitem"are not used anywhere in the static surface..result-item), source detail chunk cards, and Timeline rows are constructed as plain<div>containers with norole,aria-label, oraria-labelledby.Why this matters
Suggested fix (incremental — does not have to be one PR)
For each list surface, decide between two patterns:
role="list"+role="listitem"when the row is informational only. Addaria-labeldescribing what each row contains (e.g.aria-label="${basename}, lines ${start}-${end}, ${namespace}").role="button"+tabindex="0"when the entire row is clickable / activates an action. Match the existinghome-source-itempattern.Targets:
#results-list .result-item)app.js)Generate accessible names from the same source/line/namespace data that's already on the row.
References
docs/reports/mm-web-prod-v0.1.34-playwright-review.md