Skip to main content

Chat Widget — Accessibility Compliance

This document describes the accessibility measures implemented in the Serenity* Star Chat Widget to comply with WCAG 2.1 AA and UNE-EN 301549.


Table of Contents


1. Semantic HTML Structure

WCAG criteria: 1.3.1, 1.3.2, 1.3.5, 2.4.6, 4.1.1, 4.1.2

The widget uses proper semantic HTML elements so that the DOM structure is programmatically understandable by assistive technology:

  • Landmark regions: The chat root uses role="region" with an aria-label, making it discoverable as a named landmark. The header and footer use native <header> and <footer> elements.
  • Headings: The chat title uses a proper <h2> element (with CSS overrides to preserve visual styling), providing a heading hierarchy for screen reader navigation.
  • Message list: The message container uses role="log" to semantically communicate chronological, appendable content.
  • Individual messages: Each message bubble uses role="article" with an aria-label that distinguishes assistant messages from user messages.
  • Form controls: The text input has an associated <label> element (visually hidden via a .sr-only utility class) and a matching id/htmlFor pairing. All checkboxes (terms and conditions, communications consent) have proper associated labels.
  • Interactive elements: All clickable elements use native <button> elements rather than <div onClick>. This ensures they are focusable, keyboard-operable, and properly announced by screen readers without additional ARIA workarounds.

2. ARIA Attributes and Screen Reader Support

WCAG criteria: 1.1.1, 1.3.3, 2.4.4, 2.5.3, 4.1.2, 4.1.3

Labels on Interactive Elements

Every interactive element that lacks visible text has a descriptive aria-label sourced from the localization system. This covers all icon-only buttons across the widget — header actions, send, file upload, audio recording, feedback, scroll-to-bottom, and the FAB button.

Buttons that toggle state (expand/collapse, recording on/off, feedback selected) use dynamic labels that reflect the current state, along with appropriate ARIA state attributes (aria-expanded, aria-pressed, aria-disabled).

Decorative vs. Semantic Icons

All SVG icons used inside labeled buttons carry aria-hidden="true" and focusable="false" to prevent duplicate announcements. Icons that convey meaning independently (e.g., error indicators) use role="img" with a <title> element.

Status Announcements

Dynamic status changes are communicated to screen readers through appropriate ARIA roles:

  • Loading spinner: Uses role="status" with a visually hidden label.
  • Typing indicator: Hidden from the accessibility tree (aria-hidden="true") since message state changes are communicated through the message list's live region (see Section 3).
  • Countdown timer: Uses role="timer" with aria-live="polite" for rate-limit countdowns.
  • Error messages: Use role="alert" for immediate announcement of errors (send failures, network errors, file upload issues).
  • Conversation starters: Wrapped in a <section> with an aria-label for discoverability.

Links inside AI-generated bot messages are post-processed to improve their accessibility. Links with generic text (e.g., "click here", "read more", bare URLs) are enriched with an aria-label that includes the link's target domain, giving screen reader users enough context to decide whether to follow the link. All external links include target="_blank" with rel="noopener noreferrer".


3. Streaming Messages and Assistive Technology

WCAG criteria: 4.1.3

Streaming responses from the assistant posed the most complex accessibility challenge. Because responses arrive in incremental chunks, a naïve approach would cause screen readers to re-announce the entire growing message on every update — producing an unusable experience.

Solution: Controlled Labels on a Live Log

The message list uses role="log" with aria-live="polite". Each message has a computed aria-label that controls what screen readers announce:

  • While streaming: The label contains only the role identifier (e.g., "Assistant message") with no message content. Since the label stays static during streaming, screen readers do not produce repeated announcements as content updates visually.
  • After streaming completes: The label is updated to include the full plain-text content of the message (HTML is stripped via a conversion utility). This update is what triggers the screen reader announcement for the completed message.

Screen reader users can also navigate to any message at any time using keyboard navigation and read its content via the aria-label.


4. Keyboard Navigation

WCAG criteria: 2.1.1, 2.1.2, 2.1.4, 2.4.1, 2.4.3, 2.4.7, 2.5.2

Tab Order

The widget follows a logical top-to-bottom tab order that reflects the visual layout:

  1. Header actions (accessibility menu, expand, reset, close)
  2. Body content (load previous chats, conversation starters, messages, scroll-to-bottom)
  3. Footer (terms/checkboxes, attached files, text input, file upload, audio record, send)

When the chat opens, focus is automatically placed on the text input. When it closes, focus returns to the element that opened it (the FAB button).

Two-Level Message Navigation

Because assistant responses can be lengthy with embedded links, code blocks, and action buttons, a flat Tab-based navigation would be impractical. The widget implements a roving tabindex pattern:

  • Level 1 — Message-to-message: Arrow keys (/) navigate between messages. Home/End jump to the first/last message. Only the active message has tabindex="0".
  • Level 2 — Within a message: Pressing Enter on a focused message "drills in", enabling Tab navigation through the message's interactive children (links, buttons). Escape exits back to message-level navigation.

This follows the WAI-ARIA composite widget pattern used by treegrids and toolbars.

Focus Indicators

All interactive elements display a visible focus ring when focused via keyboard (:focus-visible). The default focus ring uses a 2px solid outline that meets the 3:1 non-text contrast requirement. On dark backgrounds (e.g., the header), the ring color adapts automatically. The previous outline: none on the textarea has been removed.

A "Skip to message input" link appears at the top of the chat body, visible only on keyboard focus. This satisfies the bypass blocks requirement for conversations with long message histories.

Additional Keyboard Support

ShortcutAction
EnterSend message (from textarea)
Shift+EnterInsert newline
EscapeClose the chat widget (floating/side-panel mode)
EscapeCancel audio recording (while recording)
EscapeClose the accessibility menu (when open)
/Navigate accessibility menu items

No single-character keyboard shortcuts are used, satisfying WCAG 2.1.4.

Focus Management

Focus is actively managed during state transitions: after loading previous chat history, focus moves to the first loaded message; when an attached file is removed, focus moves to the next attachment or falls back to the text input; after a conversation reset, focus returns to the text input.


5. Visual Accessibility

WCAG criteria: 1.4.1, 1.4.3, 1.4.4, 1.4.11, 1.4.12, 1.4.13

Color Contrast

All foreground/background color pairs in the default theme meet minimum WCAG AA contrast ratios:

  • Normal text: 4.5:1 minimum (applies to messages, timestamps, metadata, error text, placeholder text).
  • Large text: 3:1 minimum (headers, emphasized content).
  • UI components: 3:1 minimum (input borders, scrollbar thumb, focus rings, icons).

Specific fixes applied include: darkening timestamp and secondary text colors, increasing error text contrast on light error backgrounds, strengthening input border color, and improving scrollbar thumb opacity.

Color Independence

No information is conveyed by color alone. Error states always include both an icon and descriptive text alongside the colored indicator. Feedback buttons use distinct icon shapes (thumbs up/down) rather than relying on color to differentiate positive from negative.

Text Spacing Resilience

The widget does not break when users apply custom text spacing through browser extensions or settings. Layouts use flexible sizing (min-height instead of fixed height) and avoid clipping text content, accommodating WCAG 1.4.12 text spacing overrides (line-height 1.5×, letter-spacing 0.12em, word-spacing 0.16em, paragraph spacing 2×).

Tooltips

The widget uses only native HTML title attributes where applicable. No custom tooltip components are used, so browser-managed tooltips comply with WCAG 1.4.13 (dismissible, hoverable, persistent).


6. Accessibility Menu and High Contrast Mode

WCAG criteria: 1.4.3, 1.4.11, 4.1.2

The widget includes a built-in accessibility menu in the header, identifiable by a settings (gear) icon. This menu follows the WAI-ARIA Menu Button pattern with proper aria-haspopup, aria-expanded, role="menu", and role="menuitem" attributes.

High Contrast Mode

The accessibility menu provides a high contrast mode toggle. When activated, all CSS custom properties are overridden with a palette designed to exceed WCAG AAA contrast ratios (7:1 for text, 4.5:1 for UI components):

  • Black/white primary surfaces with clear visual separation.
  • Yellow focus rings on dark backgrounds for maximum visibility.
  • Solid, high-contrast borders on all interactive elements and message bubbles.
  • Dark red error text on light error backgrounds.

High contrast mode is applied with CSS !important priority to ensure user accessibility preferences always override channel-specific theming. When disabled, all overrides are cleanly removed and channel styling resumes normally.

The data-high-contrast="true" attribute is set on the root element when active, enabling additional CSS-only adjustments for edge cases not covered by CSS variables.


7. Responsive Design and User Preferences

WCAG criteria: 1.3.4, 1.4.4, 1.4.10, 2.3.1, 11.6.2, 11.7

Relative Font Sizing

All font sizes use rem units instead of fixed px values. This ensures text scales proportionally when users change their browser's base font size, satisfying WCAG 1.4.4 (Resize Text up to 200%).

Reduced Motion Support

The widget fully respects the prefers-reduced-motion: reduce user preference:

  • CSS level: A global media query disables all CSS animations and transitions within the widget (animation/transition durations set to near-zero).
  • JavaScript level: All programmatic animations (message slide-in, chat open/close, engagement message appearance, typing indicator bounce) detect the user's motion preference and are either disabled or run instantly when reduced motion is preferred.

No Disruption of Accessibility Features

Per UNE-EN 301549 §11.6.2, the widget does not interfere with platform accessibility features:

  • No user-scalable=no or maximum-scale restrictions on viewport meta tags.
  • Browser zoom (Ctrl+/Ctrl-) is never overridden.
  • Auto-scroll behavior respects manual user scrolling — if the user scrolls up during a streaming response, auto-scroll pauses and a "scroll to bottom" button appears instead.

8. Content, Language, and Predictability

WCAG criteria: 3.1.1, 3.1.2, 3.2.4, 3.3.1, 3.3.2, 3.3.3

Language Declaration

The widget's root element carries a lang attribute derived from the channel's preferredLanguage setting (defaults to "en"). This ensures screen readers use the correct pronunciation rules for the widget's content.

Consistent Naming

All user-facing labels follow a strict naming convention. The same action always uses the same label throughout the widget (e.g., "Send message" is never "Submit" or "Go"). This consistency extends across aria-label attributes, visible text, and localization keys.

Error Handling

Error messages are designed for clarity and actionability:

  • Errors are identified both visually (icon + colored text) and programmatically (role="alert" for immediate screen reader announcement).
  • Error messages describe the problem and suggest corrective action (e.g., "File exceeds the maximum size" with guidance on accepted limits).
  • Attempting to send an empty message provides accessible feedback to screen reader users.

Predictable Behavior

  • Focusing the text input does not trigger any action.
  • Typing does not cause side effects (no auto-send, no context changes).
  • The widget layout remains consistent across states — controls stay in the same position between conversations.

9. Customization and Localization

Accessibility Labels

All accessibility-related text strings (ARIA labels, screen reader announcements, status messages) can be customized using Serenity* Star's Agent Design Studio through the Chat Widget channel. English defaults are provided for all strings.

These strings can also be overridden at initialization time using the locale.accessibility configuration in the JavaScript Chat Widget. See the Localization section of the client library reference for details.

Language

The preferredLanguage property — also configurable from the Agent Design Studio — sets the lang attribute on the widget root element and determines the language context for screen readers.

CSS Custom Properties

The widget's visual theming is driven by CSS custom properties (--sc-header-bg, --sc-msg-bg, etc.). Channel owners who customize these values should ensure their color choices maintain the WCAG AA minimum contrast ratios documented above. The default values are fully compliant.

Note: When the end user activates high contrast mode from the accessibility menu, their preference takes precedence over channel-level color customization.


10. WCAG 2.1 AA Compliance Matrix

Perceivable

CriterionDescriptionStatus
1.1.1Non-text ContentCompliant — All interactive icons have text alternatives
1.3.1Info and RelationshipsCompliant — Semantic HTML elements, landmarks, heading hierarchy
1.3.2Meaningful SequenceCompliant — DOM order matches visual order
1.3.4OrientationCompliant — No orientation lock
1.3.5Identify Input PurposeCompliant — Text input has associated label
1.4.1Use of ColorCompliant — No color-only indicators
1.4.3Contrast (Minimum)Compliant — All text meets 4.5:1 / 3:1
1.4.4Resize TextCompliant — rem-based font sizing, usable at 200% zoom
1.4.10ReflowCompliant — No horizontal scroll at 320px (except code/tables)
1.4.11Non-text ContrastCompliant — UI components meet 3:1
1.4.12Text SpacingCompliant — Flexible layouts accommodate overrides
1.4.13Content on Hover/FocusCompliant — Native tooltips only

Operable

CriterionDescriptionStatus
2.1.1KeyboardCompliant — All functionality keyboard-accessible
2.1.2No Keyboard TrapCompliant — Tab exits widget naturally (role="region", no focus trap)
2.1.4Character Key ShortcutsN/A — No single-character shortcuts
2.3.1Three FlashesCompliant — Reduced motion disables animations
2.4.1Bypass BlocksCompliant — Skip link to message input
2.4.3Focus OrderCompliant — Logical top-to-bottom tab order
2.4.4Link PurposeCompliant — Generic link text enriched with domain context
2.4.6Headings and LabelsCompliant — Proper <h2> and <label> usage
2.4.7Focus VisibleCompliant — :focus-visible ring on all interactive elements
2.5.2Pointer CancellationCompliant — Actions fire on click (mouseup), not mousedown
2.5.3Label in NameCompliant — Accessible names match visible labels

Understandable

CriterionDescriptionStatus
3.1.1Language of PageCompliant — lang attribute on widget root
3.1.2Language of PartsCompliant — preferredLanguage drives lang attribute
3.2.1On FocusCompliant — No context change on focus
3.2.2On InputCompliant — No auto-submit or side effects
3.2.4Consistent IdentificationCompliant — Same action = same label everywhere
3.3.1Error IdentificationCompliant — Errors announced via role="alert"
3.3.2Labels or InstructionsCompliant — All inputs labeled
3.3.3Error SuggestionCompliant — Errors include corrective guidance

Robust

CriterionDescriptionStatus
4.1.1ParsingCompliant — Valid semantic HTML
4.1.2Name, Role, ValueCompliant — All elements properly identified
4.1.3Status MessagesCompliant — Dynamic content uses ARIA live regions and roles

UNE-EN 301549 Additional

SectionDescriptionStatus
11.6.2No Disruption of Accessibility FeaturesCompliant — No zoom restrictions, no overriding of AT settings
11.7User PreferencesCompliant — Respects prefers-reduced-motion, high contrast mode available