Skip to content

Latest commit

 

History

History
301 lines (229 loc) · 9.06 KB

File metadata and controls

301 lines (229 loc) · 9.06 KB

AccessiWeather Accessibility Guidelines

Overview

AccessiWeather is designed with accessibility as a core priority, ensuring full functionality for screen reader users and keyboard navigation. This document outlines the accessibility standards and patterns used throughout the application.

Core Principles

  1. Screen Reader Compatibility: All interactive UI elements must have proper ARIA attributes
  2. Keyboard Navigation: All functionality must be accessible via keyboard (Tab/Shift+Tab navigation)
  3. Clear Labels: Every control must have both a short label and detailed description
  4. Logical Flow: UI elements must be ordered in a way that makes sense when navigating linearly

ARIA Attribute Requirements

Required Attributes

All Toga widgets with user interaction must have:

  • aria_label: Short, concise description (< 50 characters)

    • Used by screen readers as the primary identifier
    • Should be clear and unambiguous
    • Example: "Toggle weather alerts"
  • aria_description: Detailed explanation (> 20 characters)

    • Provides context about the widget's purpose and behavior
    • Explains what the control does and what values are valid
    • Example: "Master control to enable or disable all weather alert functionality."

Widget-Specific Guidelines

Switches (Toggle Controls)

enable_alerts_switch = toga.Switch(
    "Enable weather alerts",  # Visible on-screen text
    value=True,
    id="enable_alerts_switch"
)
enable_alerts_switch.aria_label = "Toggle weather alerts"
enable_alerts_switch.aria_description = (
    "Master control to enable or disable all weather alert functionality."
)

Guidelines:

  • aria_label: Start with "Toggle" to indicate it's a switch
  • aria_description: Explain what the switch controls and the impact of changing it

NumberInput Widgets

alert_global_cooldown_input = toga.NumberInput(
    value=5,
    min=0,
    max=60,
    id="alert_global_cooldown_input"
)
alert_global_cooldown_input.aria_label = "Global notification cooldown"
alert_global_cooldown_input.aria_description = (
    "Set the minimum number of minutes to wait between any alert notifications, "
    "from 0 to 60 minutes. This prevents notification spam across all alerts."
)

Guidelines:

  • aria_label: Short description of the value being set
  • aria_description: Include valid range (min to max) and explain the purpose

Selection Dropdowns

update_channel_selection = toga.Selection(
    items=["Stable", "Beta", "Development"],
    id="update_channel_selection"
)
update_channel_selection.aria_label = "Update channel selection"
update_channel_selection.aria_description = (
    "Choose which release channel to follow for application updates."
)

Guidelines:

  • aria_label: End with "selection" to indicate it's a dropdown
  • aria_description: Explain what the selection controls

Keyboard Navigation

Navigation Order

Widgets are added to containers in the order they should be navigated:

  1. Master Controls: Primary enable/disable switches
  2. Configuration Options: Detailed settings in logical groups
  3. Action Buttons: OK, Cancel, Apply buttons

Focus Management

# Set initial focus on the most important widget
dialog.primary_widget.focus()

Guidelines:

  • Set initial focus on the most relevant widget for the user's task
  • .focus() may fail silently on some platforms - use try/except if critical

Alert Notification UI Examples

Notifications Tab Structure

The alert notifications settings tab follows this structure:

  1. Master Controls (top)

    • Enable weather alerts switch
    • Enable alert notifications switch
  2. Severity Level Filters (middle)

    • Extreme severity switch
    • Severe severity switch
    • Moderate severity switch
    • Minor severity switch
    • Unknown severity switch
  3. Rate Limiting Settings (bottom)

    • Global cooldown input (0-60 minutes)
    • Per-alert cooldown input (0-1440 minutes)
    • Max notifications per hour input (1-100)

Complete Example

# Master control switch with full accessibility
dialog.enable_alerts_switch = toga.Switch(
    "Enable weather alerts",
    value=dialog.current_settings.enable_alerts,
    style=Pack(margin_bottom=10),
    id="enable_alerts_switch",
)
dialog.enable_alerts_switch.aria_label = "Toggle weather alerts"
dialog.enable_alerts_switch.aria_description = (
    "Master control to enable or disable all weather alert functionality."
)
notifications_box.add(dialog.enable_alerts_switch)

# Rate limiting number input with full accessibility
dialog.alert_global_cooldown_input = toga.NumberInput(
    value=getattr(dialog.current_settings, "alert_global_cooldown_minutes", 5),
    min=0,
    max=60,
    style=Pack(margin_bottom=12),
    id="alert_global_cooldown_input",
)
dialog.alert_global_cooldown_input.aria_label = "Global notification cooldown"
dialog.alert_global_cooldown_input.aria_description = (
    "Set the minimum number of minutes to wait between any alert notifications, "
    "from 0 to 60 minutes. This prevents notification spam across all alerts."
)
notifications_box.add(dialog.alert_global_cooldown_input)

Testing Accessibility

Unit Tests with toga_dummy

All accessibility features must be tested:

import os
import toga
from unittest.mock import MagicMock

@pytest.fixture
def mock_app():
    """Create a mock Toga app instance with dummy backend."""
    os.environ["TOGA_BACKEND"] = "toga_dummy"
    app = toga.App("Test AccessiWeather", "org.beeware.test")
    app.config = MagicMock()
    app.on_exit = lambda: True
    yield app

def test_switch_has_aria_attributes(mock_app, mock_config_manager):
    """Verify switches have proper aria attributes."""
    dialog = SettingsDialog(app=mock_app, config_manager=mock_config_manager)
    dialog.show_and_prepare()  # Initialize UI widgets

    # Check aria_label exists and is concise
    assert dialog.enable_alerts_switch.aria_label == "Toggle weather alerts"
    assert len(dialog.enable_alerts_switch.aria_label) < 50

    # Check aria_description provides context
    assert "master control" in dialog.enable_alerts_switch.aria_description.lower()
    assert len(dialog.enable_alerts_switch.aria_description) > 20

Test Coverage Requirements

For each interactive widget, tests must verify:

  1. Widget exists and is not None
  2. aria_label is present and concise (< 50 characters)
  3. aria_description is present and informative (> 20 characters)
  4. Descriptions contain key context words
  5. NumberInput widgets have proper min/max constraints

Screen Reader Compatibility

Supported Screen Readers

  • Windows: NVDA, JAWS
  • macOS: VoiceOver
  • Linux: Orca

Testing with Screen Readers

Manual testing checklist:

  1. Navigate to settings dialog
  2. Tab through all alert widgets
  3. Verify each widget announces:
    • Widget type (switch, number input, dropdown)
    • Current value
    • aria_label
    • aria_description
  4. Verify keyboard shortcuts work (Space to toggle, Arrow keys for inputs)

Common Pitfalls

❌ Missing ARIA Attributes

# BAD: No aria attributes
cooldown_input = toga.NumberInput(value=5, min=0, max=60)
notifications_box.add(cooldown_input)

✅ Complete ARIA Attributes

# GOOD: Full aria attributes
cooldown_input = toga.NumberInput(value=5, min=0, max=60, id="cooldown_input")
cooldown_input.aria_label = "Global notification cooldown"
cooldown_input.aria_description = (
    "Set the minimum number of minutes to wait between any alert notifications, "
    "from 0 to 60 minutes. This prevents notification spam across all alerts."
)
notifications_box.add(cooldown_input)

❌ Vague Descriptions

# BAD: Too vague
switch.aria_description = "Turns on alerts"

✅ Detailed Descriptions

# GOOD: Clear and informative
switch.aria_description = (
    "Master control to enable or disable all weather alert functionality."
)

Maintenance Guidelines

Adding New Widgets

When adding any new interactive widget:

  1. Add id parameter for automated testing
  2. Set aria_label (short, < 50 chars)
  3. Set aria_description (detailed, > 20 chars)
  4. Add to appropriate container in logical navigation order
  5. Write unit tests verifying aria attributes

Code Review Checklist

Before merging UI changes:

  • All interactive widgets have aria_label
  • All interactive widgets have aria_description
  • Labels are concise (< 50 characters)
  • Descriptions are informative (> 20 characters)
  • Navigation order is logical
  • Unit tests verify aria attributes
  • Manual screen reader testing completed

References

Contact

For accessibility questions or issues:

  • Open a GitHub issue with the accessibility label
  • Tag @accessibility-team in pull requests