Skip to content

feat(frontend): Implement WCAG 2.1 AA keyboard focus management and screen reader labels in Asset Converter Modal - #1676

Merged
emdevelopa merged 2 commits into
emdevelopa:mainfrom
onejasonn:feature/fe-implement-wcag-2-1-aa-keyboard-focus-management-and-screen-reader-labels-in-asset-converter-modal
Oct 21, 2026
Merged

emdevelopa merged 2 commits into
emdevelopa:mainfrom
onejasonn:feature/fe-implement-wcag-2-1-aa-keyboard-focus-management-and-screen-reader-labels-in-asset-converter-modal

Conversation

@onejasonn

@onejasonn onejasonn commented Oct 21, 2026 •

Copy link
Copy Markdown

Summary

Implements comprehensive WCAG 2.1 AA accessibility enhancements for the Asset Converter Modal, focusing on keyboard navigation, focus management, and screen reader support.

Changes

1. Keyboard Focus Management ✅

Modal Dialog Semantics:

  • Added role="dialog" and aria-modal="true" to container
  • Added aria-labelledby and aria-describedby for proper dialog labeling
  • Converted heading to proper <h2> with id for reference

Keyboard Navigation:

  • Escape key handler: Closes modal (documented in footer kbd hint)
  • Enter key handler: Triggers conversion (existing, preserved)
  • Focus trap: Implemented via focusin event listener to keep focus within modal
  • First input receives focus on mount (existing, preserved)

Focus Indicators:

  • Enhanced all interactive elements with visible focus rings
  • Consistent 2px mint ring with 2px offset on slate-900 background
  • Applied to: back button, swap button, convert button, refresh button, all inputs
  • Meets WCAG 2.1 2.4.7 (Focus Visible) Level AA requirement

2. Screen Reader Labels & ARIA ✅

Form Inputs - Enhanced Labels:

  • Source asset code: "Source asset code (1-12 alphanumeric characters)"
  • Source issuer: "Source asset issuer address (starts with G)"
  • Amount: "Amount to convert (positive decimal number)"
  • Destination asset code: "Destination asset code (1-12 alphanumeric characters)"
  • Destination issuer: "Destination asset issuer address (starts with G)"

Hidden Help Text (sr-only):

  • Added descriptive help for each input via aria-describedby
  • Explains requirements and constraints for screen reader users
  • Example: "Enter the asset code you want to convert from. Use XLM for native Stellar Lumens..."

ARIA Attributes:

  • aria-required="true" on all required inputs
  • aria-busy on convert button during loading
  • aria-disabled on convert button when wallet not connected
  • aria-hidden="true" on decorative icons

Dialog Description:

  • Added sr-only dialog description: "Convert between Stellar assets using strict send path payment..."
  • Provides context for screen reader users entering the modal

3. Dynamic Content Announcements ✅

Live Regions:

  • Error messages: aria-live="assertive" for immediate announcement
  • Result section: aria-live="polite" + role="region" for non-intrusive updates
  • Loading state: aria-live="polite" on "Querying..." text

Detailed Result Labels:

  • Exchange rate with full description for screen readers
  • "You send" and "You receive" amounts with aria-labels
  • Slippage buffer with full explanation
  • Path converted from arrows (→) to "then" for readability
    • Visual: "XLM → USDC → EUR"
    • Screen reader: "XLM, then USDC, then EUR"

Button Context:

  • Back button: "Close asset converter and return to commands"
  • Swap button: "Swap source and destination assets" + hidden help text
  • Convert button: Context-aware label based on loading state
  • Refresh button: "Refresh quote to get updated conversion rates"

WCAG 2.1 AA Compliance

This implementation addresses the following success criteria:

Criterion Level Status Implementation
2.1.1 Keyboard A ✅ All functions operable via keyboard (Enter, Escape)
2.1.2 No Keyboard Trap A ✅ Focus trap allows Escape to exit modal
2.4.3 Focus Order A ✅ Logical tab order through form fields
2.4.7 Focus Visible AA ✅ 2px mint focus rings on all interactive elements
4.1.3 Status Messages AA ✅ aria-live regions for errors and results
1.3.1 Info and Relationships A ✅ Proper dialog semantics and fieldset/legend
4.1.2 Name, Role, Value A ✅ Complete ARIA labels and descriptions

Testing

Keyboard Navigation:

  • ✅ Tab through all form fields in logical order
  • ✅ Enter key triggers conversion
  • ✅ Escape key closes modal
  • ✅ Focus trap prevents leaving modal via Tab
  • ✅ Visible focus indicators on all interactive elements

Screen Reader (VoiceOver/NVDA):

  • ✅ Dialog announced with title and description
  • ✅ Form labels read with requirements and help text
  • ✅ Error messages announced immediately
  • ✅ Result updates announced after conversion
  • ✅ Loading state changes announced
  • ✅ All buttons have descriptive names

Visual Testing:

  • ✅ Focus rings visible against dark background
  • ✅ Color contrast maintained (mint on dark slate)
  • ✅ Layout unchanged - purely accessibility enhancements

Implementation Details

Focus Management:

// Focus trap implementation
useEffect(() => {
  const handleFocus = (e: FocusEvent) => {
    if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
      e.preventDefault();
      firstInputRef.current?.focus();
    }
  };
  document.addEventListener("focusin", handleFocus);
  return () => document.removeEventListener("focusin", handleFocus);
}, []);

Escape Key Handler:

function handleKeyDown(e: React.KeyboardEvent) {
  if (e.key === "Escape") {
    e.preventDefault();
    onBack();
  }
}

Live Region Example:

<div 
  role="alert" 
  aria-live="assertive"
  className="..."
>
  <span className="sr-only">Error: </span>{error}
</div>

Files Changed

  • frontend/src/components/AssetConverter.tsx - All accessibility enhancements

Breaking Changes

None - purely additive accessibility improvements.

Screenshots

(Add screenshots showing focus states, screen reader output if needed)

Closes #1661
Closes #1528
Closes #1529
Closes #1530

Implement comprehensive keyboard navigation and focus management:
- Add Escape key handler to close modal (documented in footer)
- Implement focus trap to keep focus within modal dialog
- Add role="dialog" and aria-modal for proper modal semantics
- Enhance all interactive elements with focus-visible indicators
- Add proper focus ring styles (2px mint ring with offset)
- Convert container div to proper dialog with ARIA attributes

Focus management ensures keyboard-only users can navigate and exit
the modal without mouse interaction, meeting WCAG 2.1 AA standards.
Enhance accessibility with detailed ARIA labels and descriptions:
- Add aria-labelledby and aria-describedby for dialog
- Add sr-only description explaining converter purpose
- Add detailed aria-labels for all form inputs with requirements
- Add hidden help text (sr-only) for each input field
- Add aria-required="true" to required inputs
- Add aria-live regions for dynamic content (error, result, loading)
- Add aria-busy state for convert button during loading
- Add descriptive labels for all numeric values in results
- Add aria-hidden="true" to decorative icons
- Convert path arrows to readable "then" for screen readers

Screen reader enhancements ensure users with visual impairments
receive complete context about form requirements, conversion results,
and dynamic state changes, meeting WCAG 2.1 AA Level A compliance.
@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@onejasonn Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@emdevelopa
emdevelopa merged commit 78dab22 into emdevelopa:main Oct 21, 2026
@vercel

vercel Bot commented Oct 21, 2026

Copy link
Copy Markdown

@Quang-231 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment