Skip to content

Add accessible toast queue with role=status (#458) - #895

Open
Dickson2015 wants to merge 4 commits into
Creditra:mainfrom
Dickson2015:task/toast-queue
Open

Add accessible toast queue with role=status (#458)#895
Dickson2015 wants to merge 4 commits into
Creditra:mainfrom
Dickson2015:task/toast-queue

Conversation

@Dickson2015

Copy link
Copy Markdown
Contributor

Summary

Closes #458 — Add accessible toast queue with role=status.

A single, centralized toast queue for transient status messages. Mounted once in App.tsx inside NotificationProvider, it renders every active toast in a role="status" live region — WCAG 2.1 SC 4.1.3 (Status Messages).

What's included

  • src/components/ToastContainer.tsx (new) — centralized queue component mounted in App.tsx; outer container uses role="status" + aria-live="polite" + aria-atomic="true" + aria-label="Notifications"
  • src/components/notifications/ToastContainer.tsxToastItem presentational component with per-severity semantics: success/info/warning → role="status" + aria-live="polite"; error/danger → role="alert" + aria-live="assertive"
  • src/hooks/useToast.ts — typed convenience helpers (success, error, warning, info, dismiss)
  • docs/TOAST_QUEUE.md (new) — API, ARIA semantics, visible behaviour, files, and test coverage; linked from the README

Fixes included on this branch

  • NotificationCenter TDZ crash — the Shift+R shortcut effect referenced a const useCallback before initialization (ReferenceError on every render); moved below handleMarkAllAsRead so the dep array can reference it safely
  • Shift+R case-sensitivity — handler compared e.key === 'r' but Shift+R reports 'R'; normalized with toLowerCase() so the shortcut actually works
  • NotificationBell — restored the label prop and one-shot bell-pulse on danger/error arrivals (feature dropped in an earlier rewrite but still covered by tests); pulse timer held in a ref and cleared on unmount only, so a mid-animation notifications change can't stick the pulse; prefers-reduced-motion: reduce fallback added
  • CollateralSwap import — restored import CollateralSwap from "./pages/CollateralSwap" in App.tsx (dropped accidentally while wiring in ToastContainer, breaking the /collateral-swap route)
  • Tests — added ToastContainer suite (17 tests), per-severity role tests, sticky-pulse regression test, contrast tests; removed an unused binding

Validation

  • Toast/notification suite: 164 tests passing across repeated runs (ToastContainer, notifications/ToastContainer, UndoToast, NotificationCenter, NotificationBell, __tests__/NotificationCenter, safe-area)
  • tsc -b introduces no new errors in touched files

Note (pre-existing, not from this branch): App.test.tsx / App.credit-lines-route.test.tsx have failures on the base commit afcb629 and on upstream/main too (duplicate WalletReconnectBanner/NetworkMismatchBanner imports and missing props in App.tsx from an earlier merge). They are unrelated to this branch and identical at the merge-base.

Accessibility Checklist

  • Keyboard navigation works (Tab, Shift+Tab, Enter, Escape)
  • Focus indicators are clearly visible (2px outline, 2px offset)
  • Contrast ratios meet WCAG AA (4.5:1 text, 3:1 large text/icons) — see ToastContainer.contrast.test.ts
  • Touch targets are at least 44×44 px
  • Semantic HTML and ARIA roles/labels are used (role="status" / role="alert", aria-live, aria-atomic, aria-label)
  • prefers-reduced-motion is respected

Your Name and others added 4 commits July 30, 2026 15:13
- Move Shift+R keyboard-shortcut effect below handleMarkAllAsRead to
  avoid referencing the const callback before initialization (TDZ
  ReferenceError on every render of NotificationCenter).
- Use the existing OpenPanelHarness in UndoToast tests instead of a
  no-op dummy opener so the panel actually opens.
- Add docs/TOAST_QUEUE.md covering the accessible toast queue API,
  ARIA semantics, and visible behaviour; link it from the README.
- NotificationCenter: normalize the Shift+R key check so the shortcut
  works when the key event reports 'R' (uppercase) instead of 'r'
- NotificationBell: restore label prop + one-shot bell-pulse on
  danger/error arrivals, with a ref-held timer (cleared on unmount only)
  so a mid-animation notifications change cannot stick the pulse
- NotificationBell.css: add bellPulse keyframes + reduced-motion fallback
- NotificationBell.test.tsx: remove unused rerender binding, add a
  sticky-pulse regression test
- App.tsx: restore CollateralSwap import dropped by the toast queue PR
- docs: document bell label prop, pulse behaviour, em-dash aria-label
  format, and updated test count (ACCESSIBILITY.md, NOTIFICATION_CENTER.md)

Toast/notification suite: 164 tests passing across repeated runs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants