Skip to content

Card and tile controls on five dashboards are mouse-only: no tab stop, no Enter/Space, no role — WCAG 2.1.1 failure, and 12 of the 21 errors failing npm run lint #1140

Description

@MOHITKOURAV01

Five dashboards implement their primary controls as bare <div onClick={...}>. A mouse
can operate them. Nothing else can: they are not in the tab order, Enter and Space do
nothing, and a screen reader announces them as plain text with no hint that they do
anything at all.

These are not decorative elements — in each case the clickable div is the feature:

File Line What the click does
src/components/AIPollutionForecast.jsx 1043 Selects a weather condition, which re-runs the forecast
src/components/HealthImpactDashboard.jsx 189 Expands a pollutant card to reveal the health guidance
src/components/HealthRiskCards.jsx 246 Expands a risk card to reveal affected-population detail
src/components/OceanAcidificationMonitor.jsx 362 Selects an ocean region — drives the entire panel below
src/components/OceanAcidificationMonitor.jsx 618 Selects a CO₂ scenario — drives the projection chart
src/components/ReportCards.jsx 138 Expands a compliance card to reveal the breakdown

The HealthImpactDashboard, HealthRiskCards and ReportCards cards each render a
ChevronDown that rotates on expand — the affordance is drawn, and then only wired to a
pointer.

This is a WCAG 2.1 2.1.1 Keyboard (Level A) failure and, because there is no role, a
4.1.2 Name, Role, Value (Level A) failure too. For an app whose stated purpose is
public health information, the collapsed detail includes the actual health guidance.

The project's own ESLint config already flags every one of these as an error, not a
warning:

src/components/AIPollutionForecast.jsx
  1043:13  error  Visible, non-interactive elements with click handlers must have at
                  least one keyboard listener   jsx-a11y/click-events-have-key-events
  1043:13  error  Avoid non-native interactive elements...
                  jsx-a11y/no-static-element-interactions

npm run lint exits 1 on main today, and these six sites are 12 of the 21 errors. The
Lint job in CI fails on every open pull request as a result, which means the gate is
providing no signal to anyone — a genuinely new lint error would look exactly like the
status quo.

Reproduce

  1. Open the Health Impact dashboard.
  2. Press Tab repeatedly.
  3. Focus never lands on any pollutant card; the health guidance behind them is unreachable.
  4. npm run lint✖ 21 errors.

Expected

Each of these becomes a real control: reachable by Tab, operable with Enter/Space,
announced with a role and an accessible name, and — for the expandable cards —
aria-expanded reflecting state, so a screen reader user knows the detail is there and
whether it is open.

The three selector-style controls (weather condition, ocean region, CO₂ scenario) are
single-choice lists, so aria-pressed on a button is the honest mapping rather than
inventing a listbox.

Note on scope

This deliberately does not touch src/components/RouteForm.jsx, whose autocomplete has the
same class of error — that one is #1135 and needs listbox/aria-activedescendant
semantics rather than a button, so it wants its own change.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions