Skip to content

fix(miner-ui): ChatComposer's message textarea has no accessible name #7440

Description

@JSONbored

Context

ChatComposer (apps/loopover-miner-ui/src/components/chat-composer.tsx) renders the chat message
input as:

<Textarea
  ref={textareaRef}
  value={value}
  onChange={...}
  onKeyDown={...}
  placeholder={placeholder}
  disabled={disabled}
  rows={1}
  className="max-h-[160px] resize-none"
/>

with no aria-label, aria-labelledby, or wrapping <label>. packages/loopover-ui-kit/src/components/textarea.tsx
(the shared primitive) is a deliberately bare wrapper around a native <textarea> — it injects no
label of its own, by design, so the caller is expected to supply one. placeholder text is not a
substitute for a programmatic accessible name (WCAG 2.1 SC 3.3.2 "Labels or Instructions" and SC 4.1.2
"Name, Role, Value"): it disappears once the user has typed anything, and its exposure to assistive
technology as an accessible name is inconsistent across browsers/screen readers, unlike aria-label.
Every other bare/icon-only interactive control audited in this codebase (theme-toggle.tsx,
npm-install.tsx's copy button, back-to-top.tsx, health-dot.tsx, mcp-version-badge.tsx)
correctly sets an explicit aria-label — this composer is the one verified exception. The existing
test file confirms this: chat-composer.test.tsx line 12 queries the textarea with the bare
screen.getByRole("textbox") (no { name: ... } option), which is exactly what you'd expect from a
control that has no accessible name to query by.

Requirements

  • Add an aria-label to the <Textarea> in ChatComposer describing its purpose for a screen-reader
    user (e.g. "Chat message" or similar — should read sensibly standing alone, not duplicate the
    visible placeholder verbatim if that would be redundant when both are announced together in any
    given screen reader).
  • The accessible name must be present regardless of the placeholder prop's value (i.e. don't derive
    the aria-label from placeholder, since callers can override placeholder and the label
    shouldn't silently follow along as user-facing hint copy changes) — hardcode a stable, descriptive
    label appropriate to what this component always is (a chat message composer), matching how
    theme-toggle.tsx's aria-label is a fixed, purpose-describing string rather than derived from
    visible copy.

Deliverables

  • ChatComposer's <Textarea> has a stable aria-label (or equivalent aria-labelledby) giving
    it a real accessible name.

Test Coverage Requirements

apps/loopover-miner-ui/** is apps/**-only UI work and outside Codecov's coverage.include/
ignore: apps/** gate, so no patch-coverage percentage applies — but a regression test is still
required per this repo's own discipline. Update
apps/loopover-miner-ui/src/chat-composer.test.tsx's existing getByRole("textbox") query (line 12)
to screen.getByRole("textbox", { name: /<the chosen label text>/i }), so the test actually asserts
an accessible name exists and pins the specific fix instead of only checking the control's role.

Expected Outcome

A screen-reader user navigating to the miner dashboard's chat composer hears a real, stable name for
the message input (not just its placeholder, which disappears once text is entered), matching the
accessible-naming standard already applied to every other interactive control audited in this pass.

Links & Resources

  • apps/loopover-miner-ui/src/components/chat-composer.tsx:57-75
  • apps/loopover-miner-ui/src/chat-composer.test.tsx:12 (query to update)
  • apps/loopover-miner-ui/src/components/theme-toggle.tsx:51 (existing aria-label precedent in the same app)

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions