Skip to content

Accessibility Implementation Guide ​

Phase 9 - UX/Design Accessibility & Glass Architecture


Table of Contents ​

  1. Overview
  2. Accessibility Standards
  3. Implementation Checklist
  4. Glass Component Accessibility
  5. Keyboard Navigation
  6. Screen Reader Support
  7. Color Contrast
  8. Testing Procedures
  9. Common Issues & Solutions

Overview ​

BayitPlus aims for WCAG 2.1 Level AA compliance, ensuring accessibility for users with disabilities including:

  • Vision impairments (blindness, color blindness, low vision)
  • Hearing impairments (deafness, hard of hearing)
  • Motor disabilities (limited dexterity, tremors)
  • Cognitive disabilities (dyslexia, ADHD)
  • Temporary disabilities (broken arm, eye surgery recovery)

Target Platforms ​

  • iOS Mobile App: VoiceOver screen reader, Dynamic Type
  • Web Interfaces: JAWS, NVDA screen readers, keyboard-only navigation
  • TV App: Siri remote keyboard mode, directional controls

Accessibility Standards ​

WCAG 2.1 Level AA Requirements ​

CriterionPriorityStatus
1.4.3 Contrast (Minimum)A⏳ In Progress
2.1.1 KeyboardA⏳ In Progress
2.1.2 No Keyboard TrapA⏳ In Progress
2.4.3 Focus OrderA⏳ In Progress
2.4.7 Focus VisibleAA⏳ In Progress
3.2.1 On FocusA✅ Complete
4.1.2 Name, Role, ValueA⏳ In Progress
4.1.3 Status MessagesAA⏳ In Progress

Target Metrics ​

MetricTargetStatus
Contrast Ratio4.5:1 (normal text)⏳ Review
Keyboard Accessible100% of interactive elements⏳ Implement
Focus IndicatorsVisible on all interactive elements⏳ Implement
Screen Reader Compatible90% of UI elements⏳ Implement
ARIA LabelsAll interactive elements⏳ Implement

Implementation Checklist ​

Phase 9A: Accessibility Enhancements (iOS Mobile App) ​

Core Accessibility (5 hours) ​

  • [ ] Add ARIA Labels to All Interactive Elements

    • [ ] VoiceCommandButton
    • [ ] VoiceSearchModal
    • [ ] VoiceStatusIndicator
    • [ ] VoiceResponseDisplay
    • [ ] VoiceSettings
    • [ ] VoiceCommandHistory
    • [ ] All navigation buttons
    • [ ] All form inputs
  • [ ] Add Accessibility Hints

    • [ ] Describe action on button press
    • [ ] Explain purpose of each input field
    • [ ] Clarify error messages
    • [ ] Provide help text for complex features
  • [ ] Enable Dynamic Type Support

    • [ ] Test with maximum text size (200%)
    • [ ] Ensure layouts adapt
    • [ ] Verify no text overflow
    • [ ] Check readability
  • [ ] Add Focus Indicators

    • [ ] Visible outline on focused elements
    • [ ] Minimum 3px indicator width
    • [ ] High contrast focus color
    • [ ] Not just color-dependent

Voice Features Accessibility (3 hours) ​

  • [ ] VoiceCommandButton Accessibility

    • [ ] Clear button label: "Start voice command"
    • [ ] Hint: "Double tap to start listening"
    • [ ] State changes announced: "Listening for command"
    • [ ] Status updates announced: "Command processed"
    • [ ] Error messages announced: "Microphone access denied"
  • [ ] VoiceSearchModal Accessibility

    • [ ] Modal announcement: "Voice search dialog opened"
    • [ ] State indicators announced in real-time
    • [ ] Transcription updates announced
    • [ ] Suggestions read as list items
    • [ ] Response text clearly announced
    • [ ] Close button always accessible
  • [ ] Voice Status Indicator Accessibility

    • [ ] Label: "Voice service status"
    • [ ] Status announced: "Ready", "Listening", "Processing"
    • [ ] Not relying on color alone
    • [ ] Text label always present

Performance & Memory (2 hours) ​

  • [ ] Optimize for Assistive Technology
    • [ ] Reduce DOM complexity for screen readers
    • [ ] Minimize announcements per action
    • [ ] Cache accessibility attributes
    • [ ] Test with various screen readers

Glass Component Audit (3 hours) ​

  • [ ] Review Glass Component Accessibility
    • [ ] [ ] GlassCard - interactive vs semantic
    • [ ] [ ] GlassButton - proper button semantics
    • [ ] [ ] GlassModal - focus trap and restoration
    • [ ] [ ] GlassInput - label associations
    • [ ] [ ] GlassAlert - role="alert" for announcements
    • [ ] [ ] GlassCheckbox - proper state handling
    • [ ] [ ] GlassRadio - group labeling
    • [ ] [ ] GlassSelect - keyboard support

Phase 9B: Testing & Validation (2 hours) ​

  • [ ] VoiceOver Testing (iOS)

    • [ ] Enable Settings → Accessibility → VoiceOver
    • [ ] Test navigation with swipe gestures
    • [ ] Verify all content announced
    • [ ] Check action labels clear
    • [ ] Test with common gestures
    • [ ] Verify reading order logical
  • [ ] Keyboard Navigation Testing

    • [ ] Test Tab/Shift+Tab navigation
    • [ ] Verify focus order logical
    • [ ] Check no keyboard traps
    • [ ] Test Space/Enter on buttons
    • [ ] Verify form submission with keyboard
    • [ ] Test escape to close modals
  • [ ] Screen Reader Testing

    • [ ] JAWS (Windows)
    • [ ] NVDA (Windows)
    • [ ] VoiceOver (Mac)
    • [ ] TalkBack (Android, if applicable)
    • [ ] Narrator (Windows)
  • [ ] Color Contrast Verification

    • [ ] Use WebAIM Contrast Checker
    • [ ] Test all text on backgrounds
    • [ ] Check focus indicators
    • [ ] Verify error/success colors
    • [ ] Test colorblind simulation

Phase 9C: Documentation (1 hour) ​

  • [ ] Create Accessibility Testing Guide
  • [ ] Document Accessibility Patterns
  • [ ] Create Component Accessibility Checklist
  • [ ] Document Known Limitations

Glass Component Accessibility ​

Current Status ​

Glass Components use Tailwind CSS and are built with accessibility in mind.

GlassButton ​

Current:

tsx
<GlassButton>
  Click me
</GlassButton>

Enhanced:

tsx
<GlassButton
  aria-label="Open voice command modal"
  aria-describedby="voice-button-hint"
  accessible
  accessibilityHint="Double tap to start listening for voice commands"
  onPress={handleOpenVoice}
>
  <Microphone size={20} />
</GlassButton>
<Text id="voice-button-hint" hidden>
  Use voice to search and control playback
</Text>

GlassModal ​

Ensure:

  • Modal announced as dialog
  • Focus trapped inside modal
  • Escape key closes modal
  • Focus restored on close
  • Title associated with modal
tsx
<GlassModal
  accessible
  accessibilityRole="dialog"
  accessibilityLabel="Voice Search Dialog"
  isVisible={isOpen}
>
  <Text accessibilityRole="header">Voice Search</Text>
  {/* Content */}
</GlassModal>

GlassInput ​

Ensure:

  • Label associated with input
  • Placeholder not substitute for label
  • Error messages announced
  • Input type correct (email, password, etc.)
tsx
<Text accessibilityLabel="Search query">Search</Text>
<GlassInput
  aria-label="Search query"
  aria-describedby="search-error"
  placeholder="What do you want to watch?"
  value={query}
  onChangeText={setQuery}
/>
{error && (
  <Text id="search-error" role="alert" style={{color: 'red'}}>
    {error}
  </Text>
)}

GlassCard ​

Ensure:

  • If interactive, use Button component
  • Provide semantic role
  • Add appropriate ARIA labels
tsx
<GlassCard
  accessible
  accessibilityRole={onPress ? 'button' : 'article'}
  accessibilityLabel="Featured movie: Fauda"
  onPress={handlePress}
>
  {/* Content */}
</GlassCard>

Keyboard Navigation ​

Tab Order Strategy ​

Priority Order:

  1. Skip to main content link
  2. Navigation elements (menu, search)
  3. Main content interactive elements
  4. Footer links
  5. Secondary controls

Implementation ​

tsx
// Define tabIndex explicitly
<button tabIndex={0}>Primary Action</button>
<button tabIndex={1}>Secondary Action</button>

// For React Native, use accessible prop
<TouchableOpacity accessible={true}>
  {/* Content */}
</TouchableOpacity>

// For complex modals, manage focus
useEffect(() => {
  firstButtonRef.current?.focus();
}, [isModalOpen]);

Testing Checklist ​

  • [ ] Tab moves forward through elements
  • [ ] Shift+Tab moves backward
  • [ ] Tab order is logical (left-to-right, top-to-bottom)
  • [ ] No keyboard traps (easy to exit from any element)
  • [ ] Skip links work (if applicable)
  • [ ] Focus always visible
  • [ ] Modal focus trapped while open

Screen Reader Support ​

Minimum Required Attributes ​

Every interactive element needs:

  1. Accessible Name (what is it?)

    aria-label="Start voice command"
    // or
    <label>Start Voice Command</label>
  2. Role (what type of element?)

    role="button" // or native <button>
    role="alert" // for status messages
    role="search" // for search areas
  3. State (what state is it in?)

    aria-pressed="true" // toggle button state
    aria-expanded="false" // collapsible state
    aria-checked="true" // checkbox state
  4. Description (additional context?)

    aria-describedby="help-text"

Common Announcements ​

Screen readers will announce these automatically:

ElementAnnouncement
<button>"Button. [Label]. Double-tap to activate"
<input>"[Label]. Editable text field"
<select>"[Label]. Popup button"
role="alert""[Message]" (immediately announced)
Modal"Dialog opened. [Title]"

Testing with Screen Readers ​

iOS VoiceOver:

1. Go to Settings → Accessibility → VoiceOver → On
2. Swipe right → Next element
3. Swipe left → Previous element
4. Swipe up/down → Read entire screen
5. Double-tap → Activate
6. Two-finger triple-tap → Read all

Windows NVDA:

Tab → Next element
Shift+Tab → Previous element
Arrow keys → Navigate within element
Enter/Space → Activate button
Alt+F4 → Close window
Insert+H → Help (while in NVDA)

Color Contrast ​

Requirements ​

Text TypeMinimum RatioAA Standard
Normal text4.5:14.5:1
Large text (18pt+)3:13:1
UI components3:13:1
Focus indicator3:13:1

BayitPlus Dark Theme Colors ​

Approved Combinations:

BackgroundTextRatioStatus
#0F172A (dark)#F1F5F9 (light)14.5:1✅ Excellent
#1E293B (gray)#F1F5F9 (light)10.8:1✅ Excellent
#334155 (gray)#E2E8F0 (lighter)7.2:1✅ Good
#3B82F6 (blue)#FFFFFF (white)5.6:1✅ Good
#10B981 (green)#FFFFFF (white)4.5:1✅ Minimum

Colors to Avoid ​

❌ Dark gray (#475569) on dark background (#1E293B) = 2.1:1 (FAILS) ❌ Light gray (#CBD5E1) on light gray (#E2E8F0) = 1.5:1 (FAILS)

Testing Tools ​


Testing Procedures ​

Phase 9 Testing Timeline ​

1. Automated Testing (30 min) ​

bash
# Install accessibility linter
npm install --save-dev eslint-plugin-jsx-a11y

# Run checks
npm run lint -- --ext .tsx --plugin jsx-a11y

2. Manual Testing with VoiceOver (60 min) ​

Test Script:

  1. Enable VoiceOver
  2. Navigate home screen entirely using swipes
  3. Activate voice search
  4. Say a command
  5. Hear response
  6. Disable voice feature
  7. Verify all elements still accessible

3. Color Contrast Verification (30 min) ​

bash
# Use WebAIM contrast checker for each color pair
# Test in both light and dark modes
# Verify colorblind simulator

4. Keyboard Navigation Testing (30 min) ​

Test all of:

  • Home Screen Tab navigation
  • Search Screen Tab + Enter flow
  • Voice Search Modal Tab order
  • Settings Dialog Tab trap test
  • Video Player Controls keyboard
  • Settings form keyboard submission

5. Screen Reader Testing (60 min) ​

Test with:

  • VoiceOver (iOS) - 30 min
  • JAWS (Windows, if available) - 15 min
  • NVDA (Windows, if available) - 15 min

Common Issues & Solutions ​

Issue 1: Text Not Announced by Screen Reader ​

Cause: Element not properly labeled Solution:

tsx
// ❌ Bad - No label
<button>🎤</button>

// ✅ Good - Explicit label
<button aria-label="Start voice command">🎤</button>

// ✅ Also good - Text label
<button>
  <Icon /> Start Voice
</button>

Issue 2: Keyboard Focus Not Visible ​

Cause: CSS removes focus outline Solution:

tsx
// ❌ Bad
button {
  outline: none; /* DON'T DO THIS */
}

// ✅ Good
button:focus-visible {
  outline: 3px solid #3B82F6;
  outline-offset: 2px;
}

Issue 3: Modal Focus Escapes Modal ​

Cause: Focus not properly trapped Solution:

tsx
useEffect(() => {
  if (isModalOpen) {
    // Store previous focus
    const previousFocus = document.activeElement;

    // Move focus to modal
    firstButtonRef.current?.focus();

    return () => {
      // Restore focus when modal closes
      (previousFocus as HTMLElement).focus();
    };
  }
}, [isModalOpen]);

Issue 4: Color Combinations Fail Contrast Check ​

Cause: Insufficient color contrast Solution: Use approved color combinations above, or:

tsx
// ❌ Bad - 2.1:1 ratio
<Text style={{ color: '#475569', backgroundColor: '#1E293B' }}>
  Insufficient contrast
</Text>

// ✅ Good - 10.8:1 ratio
<Text style={{ color: '#F1F5F9', backgroundColor: '#1E293B' }}>
  Proper contrast
</Text>

Issue 5: Dynamic Content Not Announced ​

Cause: Screen reader doesn't know content changed Solution:

tsx
// Use role="alert" for important updates
<Text
  role="alert"
  aria-live="polite"
  aria-atomic="true"
>
  Command processed successfully
</Text>

// For status indicators
<Text aria-live="polite" aria-label="Voice service status">
  {stage === 'listening' ? 'Listening...' : 'Ready'}
</Text>

Glass Library Architecture Decision ​

Current Status ​

The project uses @bayit/shared-components for Glass UI components.

Pros:

  • Clear branding as "Glass" design system
  • Better market positioning
  • Short, memorable npm package name
  • Aligns with glassmorphism aesthetic

Cons:

  • Minor refactoring effort (3-4 hours)
  • All imports need updating
  • Package rename on npm

Implementation (estimated 3-4 hours):

bash
# 1. Rename npm package
npm unpublish @bayit/shared-components
npm publish as @bayit/glass

# 2. Update all imports
# Search/replace across codebase:
# @bayit/shared-components → @bayit/glass

# 3. Update documentation
# package.json in all packages
# README and setup guides

Option B: Keep Current Name + Migrate to Tailwind ​

Pros:

  • More flexible styling
  • Broader appeal to developers
  • More customization options

Cons:

  • Very large refactoring (1-2 weeks)
  • Removes established component library
  • More onboarding complexity
  • Delays production launch

Not Recommended: Given production deadline, this option would delay launch significantly.

Recommendation ​

→ Option A: Rename to @bayit/glass

Glass is already glassmorphic in design. Renaming to @bayit/glass makes this clear and creates strong branding. This can be done quickly (3-4 hours) and doesn't impact functionality.


Accessibility Checklist Summary ​

Before Production Launch ​

  • [ ] All interactive elements have accessible names
  • [ ] Keyboard navigation works completely
  • [ ] Color contrast meets WCAG AA
  • [ ] Focus indicators visible on all elements
  • [ ] Screen reader tested on iOS VoiceOver
  • [ ] No keyboard traps
  • [ ] Modal focus properly managed
  • [ ] Status messages announced
  • [ ] Error messages announced and clear
  • [ ] Dynamic content announcements work
  • [ ] Voice features fully accessible
  • [ ] Settings accessible to all users
  • [ ] No reliance on color alone for information

Sign-Off Criteria ​

✅ WCAG 2.1 Level AA compliance verified ✅ VoiceOver testing successful ✅ Keyboard navigation complete ✅ Color contrast verified ✅ No accessibility blockers


Resources ​


Phase 9 Status: Accessibility Guide Complete ✅ Next: Phase 10 - Documentation


Last Updated: January 21, 2026 Version: 1.0 Status: Ready for Implementation

Released under the MIT License.