Overview

Beep Controls are designed with accessibility as a first-class concern. The framework provides built-in support for high-contrast mode, screen reader integration, keyboard navigation, and configurable focus indicators. This guide explains how to use these features and how to ensure your own custom controls meet the same bar.

Accessibility is not a bolt-on feature — it is woven into BaseControl so that every control inherits it automatically. You need to opt in to enable the full stack, but you should never need to opt out.

HighContrastMode

HighContrastMode is a global toggle that tells all Beep controls to use system high-contrast colors instead of theme colors. When enabled, controls ignore the active theme's palette and read from SystemColors, ensuring legibility for users who have enabled Windows High Contrast.

static void Main()
{
    ApplicationConfiguration.Initialize();

    // Detect system high-contrast setting on startup
    if (SystemInformation.HighContrast)
    {
        BeepThemesManager.EnableHighContrastMode();
    }

    // Or expose a toggle in your settings
    SystemEvents.UserPreferenceChanged += (s, e) =>
    {
        if (e.Category == UserPreferenceCategory.Accessibility)
        {
            if (SystemInformation.HighContrast)
                BeepThemesManager.EnableHighContrastMode();
            else
                BeepThemesManager.DisableHighContrastMode();
        }
    };

    Application.Run(new MainForm());
}

When HighContrastMode is active, BaseControl.ApplyControlStyle() automatically substitutes theme colors with high-contrast equivalents. No control-level code changes needed.

// Inside BaseControl.ApplyControlStyle():
if (BeepThemesManager.HighContrastMode)
{
    BackColor = SystemColors.Window;
    ForeColor = SystemColors.WindowText;
    _borderPen = new Pen(SystemColors.WindowText, 2f); // Thicker borders
}
else
{
    var theme = BeepThemesManager.ActiveTheme;
    BackColor = theme.BackColor;
    ForeColor = theme.ForeColor;
}

ScreenReaderSupport

ScreenReaderSupport automatically populates AccessibleName, AccessibleDescription, and AccessibleRole on all Beep controls. Enable it globally in Program.cs:

static void Main()
{
    ApplicationConfiguration.Initialize();
    BeepThemesManager.ApplyTheme("MaterialBlue");
    ScreenReaderSupport.Enable(); // Activates accessibility properties globally

    Application.Run(new MainForm());
}

With ScreenReaderSupport enabled, controls automatically derive their accessible names from nearby labels, button text, or the Caption property:

// ScreenReaderSupport automatically pairs labels with inputs
var nameLabel = new BeepLabel { Text = "Full Name" };
var nameBox = new BeepTextBox();
// nameBox.AccessibleName is automatically set to "Full Name"

// For standalone controls, set explicitly:
myButton.Text = "Save";
myButton.AccessibleName = "Save Document"; // Override for more context
myButton.AccessibleDescription = "Saves the current document to disk";

Keyboard Navigation

Every Beep control supports keyboard navigation out of the box. The standard navigation model includes:

KeyBehavior
Tab / Shift+TabMove focus forward/backward through controls in TabIndex order
Enter / SpaceActivate focused button, checkbox, or toggle
Arrow KeysNavigate within grids, lists, trees, menus, and tab controls
EscapeClose modal dialogs, popups, and dropdowns
Home / EndJump to first/last item in a list or grid
Page Up / Page DownScroll a page in scrollable areas
Alt+LetterActivate menu items with mnemonic shortcuts

// Set logical tab order for form controls
nameTextBox.TabIndex = 0;
emailTextBox.TabIndex = 1;
passwordTextBox.TabIndex = 2;
submitButton.TabIndex = 3;

// Mnemonics — Alt+S activates this button
submitButton.Text = "&Save";

// Custom key handling for non-standard controls
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Control | Keys.F))
    {
        searchBox.Focus();
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

Focus Indicators and Tab Order

BaseControl paints a visible focus rectangle whenever the control has keyboard focus. You can customize the focus indicator thickness, color, and style:

// Per-control focus indicator customization
myButton.FocusIndicatorColor = Color.FromArgb(0, 120, 215);
myButton.FocusIndicatorWidth = 3;
myButton.FocusIndicatorStyle = FocusBorderStyle.Solid;

// Style options
// Solid    — 2px-4px solid border in FocusIndicatorColor
// Dashed   — standard Windows focus rectangle (dotted)
// Glow     — soft glow around the control perimeter

Never disable focus indicators. Keyboard-only and low-vision users rely on them to know where they are on the form. If you customize, ensure high contrast against the control's background:

// Bad — invisible focus indicator on a dark control
darkPanel.FocusIndicatorColor = Color.DarkBlue;

// Good — visible indicator regardless of background
darkPanel.FocusIndicatorColor = Color.Cyan;

Caption Accessibility

Beep controls support a Caption property that serves as the accessible label. When ScreenReaderSupport is enabled:

  • Caption → populates AccessibleName automatically
  • CaptionDescription → populates AccessibleDescription
  • Contextual hints propagate to the Windows accessibility API
// Caption on a disabled control — screen reader reads "Date of Birth, disabled"
dobPicker.Caption = "Date of Birth";
dobPicker.CaptionDescription = "Select your birth date from the calendar";
dobPicker.Enabled = false;

// Validation errors + captions
emailBox.Caption = "Email Address";
emailBox.ValidationError = "Please enter a valid email";
// Screen reader announces: "Email Address, error: Please enter a valid email"

Region-Based Hit Testing

For controls with non-rectangular shapes (rounded corners, circular buttons, custom paths), Beep supports region-based hit testing through HitTestRegion. This ensures that clicks outside the visible region are not captured, which is important for users with motor impairments who may click near the control's edge.

public class CircularButton : BaseControl
{
    private Region _hitRegion;

    public CircularButton()
    {
        Size = new Size(60, 60);
        UpdateHitRegion();
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        UpdateHitRegion();
    }

    private void UpdateHitRegion()
    {
        _hitRegion?.Dispose();
        using var path = new GraphicsPath();
        path.AddEllipse(ClientRectangle);
        _hitRegion = new Region(path);
        HitTestRegion = _hitRegion;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        using var path = new GraphicsPath();
        path.AddEllipse(ClientRectangle);
        e.Graphics.FillPath(_backBrush, path);
    }
}

Set HitTestRegion on any BaseControl descendant to define a custom clickable area. Clicks outside the region pass through to controls beneath.

ARIA Equivalent Properties

Beep controls map logical roles and states to the Windows accessibility API, providing the equivalent of ARIA attributes for desktop applications. Most are automatic; the table below shows the mapping for custom scenarios:

Beep PropertyWindows APIARIA EquivalentAutomatically Set?
CaptionAccessibleNamearia-labelYes (via ScreenReaderSupport)
CaptionDescriptionAccessibleDescriptionaria-descriptionYes
ControlRoleAccessibleRoleroleYes (derived from control type)
ValidationErrorLiveRegion updatearia-invalidYes (announced on change)
EnabledState flagaria-disabledYes
IsCheckedState flagaria-checkedYes (checkboxes/toggles)

// Manually set role for custom controls
public class RatingStars : BaseControl
{
    public RatingStars()
    {
        ControlRole = AccessibleRole.Slider;
        Caption = "Rating";
        CaptionDescription = "Rate this item from 1 to 5 stars";
    }
}

// Override for dynamic accessible descriptions
protected override AccessibleObject CreateAccessibilityInstance()
{
    return new RatingAccessibleObject(this);
}

Designing Accessible Themes

When creating a custom IBeepTheme, validate these accessibility requirements:

  • Contrast ratio ≥ 4.5:1 for normal text (WCAG 2.1 AA)
  • Contrast ratio ≥ 3:1 for large text (≥ 18px or 14px bold)
  • Non-color indicators — use icons, text labels, or patterns alongside color (e.g., error state = red border + icon)
  • Minimum touch target 44 × 44px at native resolution
  • Focus indicator visible against all background colors in the theme
  • Disabled state clearly distinguishable — not just lighter color, but reduced opacity + different visual treatment

Accessibility Checklist

Use this checklist as a pre-release gate for any Beep-powered form:

  • ScreenReaderSupport.Enable() is called at startup
  • HighContrastMode detection and UserPreferenceChanged handler are wired up
  • All interactive controls are reachable by Tab / Shift+Tab
  • TabIndex follows a logical reading order (left-to-right, top-to-bottom)
  • Every control without visible text has Caption set
  • Focus indicators are visible against all background colors
  • Color is never the sole differentiator of state (use icons, text, or patterns too)
  • Modal dialogs and dropdowns close with Escape
  • All text meets 4.5:1 contrast ratio in all themes
  • Touch targets are ≥ 44 × 44px
  • Forms degrade gracefully at 150% and 200% DPI
  • Non-rectangular controls use HitTestRegion