@chat21/chat21-web-widget 5.1.34 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.angular-mcp-cache/package.json +1 -0
- package/.cursor/angular18-accessibility-auditor-skill.md +442 -0
- package/.cursor/mcp.json +15 -0
- package/.github/workflows/playwright.yml +27 -0
- package/CHANGELOG.md +25 -0
- package/Dockerfile +4 -5
- package/README.md +1 -1
- package/angular.json +21 -3
- package/docs/ACCESSIBILITY-STATEMENT.md +388 -0
- package/docs/TILEDESK_WIDGET_ACCESSIBILITY_ALIGNMENT.md +60 -0
- package/docs/TILEDESK_WIDGET_ACCESSIBILITY_STATEMENT_COMPLETE.md +386 -0
- package/env.sample +3 -2
- package/mocks/voice-websocket-mock/server.cjs +245 -0
- package/package.json +10 -3
- package/playwright.config.ts +41 -0
- package/src/app/app.component.html +2 -2
- package/src/app/app.component.scss +25 -14
- package/src/app/app.component.spec.ts +21 -6
- package/src/app/app.module.ts +13 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.html +25 -11
- package/src/app/component/conversation-detail/conversation/conversation.component.scss +38 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.spec.ts +644 -75
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +70 -2
- package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.html +25 -13
- package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.spec.ts +123 -5
- package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +1 -0
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +23 -10
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +18 -0
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.spec.ts +241 -149
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +8 -5
- package/src/app/component/conversation-detail/conversation-emojii/conversation-emojii.component.spec.ts +53 -3
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +203 -110
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +212 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.spec.ts +458 -78
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +288 -76
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +113 -53
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.scss +12 -4
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.spec.ts +274 -29
- package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.html +23 -9
- package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.spec.ts +80 -8
- package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.html +29 -23
- package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.spec.ts +185 -16
- package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.ts +34 -14
- package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.html +46 -0
- package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.scss +83 -0
- package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.ts +192 -0
- package/src/app/component/error-alert/error-alert.component.spec.ts +65 -5
- package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html +16 -7
- package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.scss +21 -0
- package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.spec.ts +89 -7
- package/src/app/component/form/form-builder/form-builder.component.html +1 -1
- package/src/app/component/form/form-builder/form-builder.component.spec.ts +163 -21
- package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.html +8 -4
- package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.scss +10 -5
- package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.spec.ts +90 -16
- package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.ts +26 -0
- package/src/app/component/form/inputs/form-label/form-label.component.spec.ts +45 -11
- package/src/app/component/form/inputs/form-radio-button/form-radio-button.component.spec.ts +24 -6
- package/src/app/component/form/inputs/form-select/form-select.component.spec.ts +14 -5
- package/src/app/component/form/inputs/form-text/form-text.component.html +14 -12
- package/src/app/component/form/inputs/form-text/form-text.component.scss +11 -1
- package/src/app/component/form/inputs/form-text/form-text.component.spec.ts +113 -17
- package/src/app/component/form/inputs/form-text/form-text.component.ts +35 -3
- package/src/app/component/form/inputs/form-textarea/form-textarea.component.html +13 -11
- package/src/app/component/form/inputs/form-textarea/form-textarea.component.scss +6 -5
- package/src/app/component/form/inputs/form-textarea/form-textarea.component.spec.ts +149 -13
- package/src/app/component/form/inputs/form-textarea/form-textarea.component.ts +26 -0
- package/src/app/component/form/prechat-form/prechat-form.component.html +14 -11
- package/src/app/component/form/prechat-form/prechat-form.component.spec.ts +102 -10
- package/src/app/component/form/prechat-form/prechat-form.component.ts +8 -1
- package/src/app/component/form/prechat-form-test-mock.ts +35 -0
- package/src/app/component/home/home.component.html +38 -31
- package/src/app/component/home/home.component.scss +4 -2
- package/src/app/component/home/home.component.spec.ts +226 -11
- package/src/app/component/home-conversations/home-conversations.component.html +30 -26
- package/src/app/component/home-conversations/home-conversations.component.scss +3 -0
- package/src/app/component/home-conversations/home-conversations.component.spec.ts +212 -36
- package/src/app/component/last-message/last-message.component.html +15 -9
- package/src/app/component/last-message/last-message.component.scss +16 -2
- package/src/app/component/last-message/last-message.component.spec.ts +204 -23
- package/src/app/component/launcher-button/launcher-button.component.html +8 -13
- package/src/app/component/launcher-button/launcher-button.component.spec.ts +104 -8
- package/src/app/component/list-all-conversations/list-all-conversations.component.html +12 -17
- package/src/app/component/list-all-conversations/list-all-conversations.component.scss +2 -0
- package/src/app/component/list-conversations/list-conversations.component.html +22 -22
- package/src/app/component/menu-options/menu-options.component.html +30 -20
- package/src/app/component/menu-options/menu-options.component.spec.ts +125 -9
- package/src/app/component/message/audio/audio.component.html +13 -15
- package/src/app/component/message/audio/audio.component.spec.ts +140 -5
- package/src/app/component/message/audio/audio.component.ts +1 -5
- package/src/app/component/message/audio-sync/audio-sync.component.html +18 -0
- package/src/app/component/message/audio-sync/audio-sync.component.scss +65 -0
- package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +112 -0
- package/src/app/component/message/audio-sync/audio-sync.component.ts +714 -0
- package/src/app/component/message/avatar/avatar.component.html +2 -2
- package/src/app/component/message/avatar/avatar.component.spec.ts +99 -7
- package/src/app/component/message/bubble-message/bubble-message.component.html +41 -51
- package/src/app/component/message/bubble-message/bubble-message.component.scss +54 -1
- package/src/app/component/message/bubble-message/bubble-message.component.spec.ts +147 -57
- package/src/app/component/message/bubble-message/bubble-message.component.ts +95 -13
- package/src/app/component/message/buttons/action-button/action-button.component.html +3 -4
- package/src/app/component/message/buttons/action-button/action-button.component.spec.ts +49 -5
- package/src/app/component/message/buttons/link-button/link-button.component.scss +5 -8
- package/src/app/component/message/buttons/link-button/link-button.component.spec.ts +50 -5
- package/src/app/component/message/buttons/text-button/text-button.component.spec.ts +44 -5
- package/src/app/component/message/carousel/carousel.component.html +29 -16
- package/src/app/component/message/carousel/carousel.component.scss +20 -8
- package/src/app/component/message/carousel/carousel.component.spec.ts +80 -3
- package/src/app/component/message/carousel/carousel.component.ts +16 -0
- package/src/app/component/message/frame/frame.component.html +9 -4
- package/src/app/component/message/frame/frame.component.spec.ts +34 -15
- package/src/app/component/message/frame/frame.component.ts +7 -2
- package/src/app/component/message/html/html.component.html +1 -1
- package/src/app/component/message/html/html.component.scss +1 -1
- package/src/app/component/message/html/html.component.spec.ts +24 -7
- package/src/app/component/message/image/image.component.html +12 -10
- package/src/app/component/message/image/image.component.scss +16 -0
- package/src/app/component/message/image/image.component.spec.ts +101 -15
- package/src/app/component/message/image/image.component.ts +90 -51
- package/src/app/component/message/info-message/info-message.component.spec.ts +26 -14
- package/src/app/component/message/json-sources/json-sources.component.html +6 -5
- package/src/app/component/message/json-sources/json-sources.component.scss +26 -18
- package/src/app/component/message/json-sources/json-sources.component.ts +41 -0
- package/src/app/component/message/like-unlike/like-unlike.component.html +7 -9
- package/src/app/component/message/like-unlike/like-unlike.component.spec.ts +31 -3
- package/src/app/component/message/return-receipt/return-receipt.component.spec.ts +38 -17
- package/src/app/component/message/text/text.component.html +3 -3
- package/src/app/component/message/text/text.component.scss +80 -86
- package/src/app/component/message/text/text.component.spec.ts +106 -13
- package/src/app/component/message-attachment/message-attachment.component.spec.ts +134 -13
- package/src/app/component/selection-department/selection-department.component.html +21 -23
- package/src/app/component/selection-department/selection-department.component.spec.ts +159 -14
- package/src/app/component/selection-department/selection-department.component.ts +8 -1
- package/src/app/component/send-button/send-button.component.html +5 -13
- package/src/app/component/send-button/send-button.component.spec.ts +2 -2
- package/src/app/component/star-rating-widget/star-rating-widget.component.html +51 -81
- package/src/app/directives/tooltip.directive.spec.ts +8 -4
- package/src/app/modals/confirm-close/confirm-close.component.html +20 -8
- package/src/app/modals/confirm-close/confirm-close.component.scss +3 -0
- package/src/app/modals/confirm-close/confirm-close.component.spec.ts +13 -4
- package/src/app/modals/confirm-close/confirm-close.component.ts +8 -1
- package/src/app/pipe/html-entites-encode.pipe.spec.ts +35 -2
- package/src/app/pipe/marked.pipe.spec.ts +38 -2
- package/src/app/pipe/marked.pipe.ts +51 -41
- package/src/app/providers/app-config.service.ts +4 -2
- package/src/app/providers/brand.service.spec.ts +23 -2
- package/src/app/providers/brand.service.ts +1 -1
- package/src/app/providers/global-settings.service.spec.ts +1009 -14
- package/src/app/providers/global-settings.service.ts +40 -2
- package/src/app/providers/json-sources-parser.service.ts +13 -1
- package/src/app/providers/translator.service.ts +24 -7
- package/src/app/providers/tts-audio-playback-coordinator.service.spec.ts +116 -0
- package/src/app/providers/tts-audio-playback-coordinator.service.ts +122 -0
- package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +12 -0
- package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +156 -0
- package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +39 -0
- package/src/app/providers/voice/audio.types.ts +40 -0
- package/src/app/providers/voice/vad.service.spec.ts +28 -0
- package/src/app/providers/voice/vad.service.ts +70 -0
- package/src/app/providers/voice/voice-streaming.service.spec.ts +23 -0
- package/src/app/providers/voice/voice-streaming.service.ts +702 -0
- package/src/app/providers/voice/voice-streaming.types.ts +112 -0
- package/src/app/providers/voice/voice.service.spec.ts +227 -0
- package/src/app/providers/voice/voice.service.ts +969 -0
- package/src/app/sass/_variables.scss +2 -0
- package/src/app/sass/animations.scss +19 -1
- package/src/app/shims/onnxruntime-web-wasm.ts +4 -0
- package/src/app/utils/globals.ts +14 -0
- package/src/app/utils/utils-resources.ts +1 -1
- package/src/assets/i18n/en.json +128 -100
- package/src/assets/i18n/es.json +128 -100
- package/src/assets/i18n/fr.json +128 -100
- package/src/assets/i18n/it.json +128 -98
- package/src/assets/onnx/ort-wasm-simd-threaded.mjs +59 -0
- package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
- package/src/assets/sounds/keyboard.mp3 +0 -0
- package/src/assets/vad/silero_vad_legacy.onnx +0 -0
- package/src/assets/vad/vad.worklet.bundle.min.js +1 -0
- package/src/chat21-core/models/message.ts +2 -1
- package/src/chat21-core/providers/chat-manager.spec.ts +72 -0
- package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +3 -2
- package/src/chat21-core/providers/firebase/firebase-init-service.ts +5 -5
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +12 -0
- package/src/chat21-core/providers/scripts/script.service.spec.ts +12 -2
- package/src/chat21-core/utils/utils-message.ts +7 -0
- package/src/widget-config-template.json +3 -1
- package/src/widget-config.json +28 -27
- package/tests/widget-form-rich.spec.ts +67 -0
- package/tests/widget-index-dev-settings.spec.ts +52 -0
- package/tests/widget-twp-iframe.spec.ts +39 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Accessibility Conformance Statement
|
|
2
|
+
## Tiledesk Web Widget — Angular 18
|
|
3
|
+
|
|
4
|
+
> **Consolidated edition:** For the merged document (alignment narrative + all tables, gap-oriented sections removed by policy), see [`TILEDESK_WIDGET_ACCESSIBILITY_STATEMENT_COMPLETE.md`](./TILEDESK_WIDGET_ACCESSIBILITY_STATEMENT_COMPLETE.md).
|
|
5
|
+
|
|
6
|
+
| Field | Value |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Product | Tiledesk Web Widget |
|
|
9
|
+
| Package | `@chat21/chat21-web-widget` |
|
|
10
|
+
| Version | 5.1.33 |
|
|
11
|
+
| Stack | Angular 18.2.x (NgModule bootstrap), Angular CDK 17 (`A11yModule`), iframe-hosted (`launch.js`) |
|
|
12
|
+
| Standards reviewed | WCAG 2.2 Level AA, WAI-ARIA 1.2 Authoring Practices, EN 301 549 v3.2.1 (chapters 9, 11) |
|
|
13
|
+
| Document language | English |
|
|
14
|
+
| Last update | 2026-05-11 |
|
|
15
|
+
|
|
16
|
+
> This document is meant to be shipped to clients and integrators that need a transparent
|
|
17
|
+
> view of where the widget stands against accessibility regulations. It is a living
|
|
18
|
+
> statement: every section is verifiable directly in the source tree referenced here.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. Conformance Summary
|
|
23
|
+
|
|
24
|
+
| Area | Score (0–5) | Conformance level achieved |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| Semantic HTML | 4.5 | WCAG 2.2 AA |
|
|
27
|
+
| Keyboard accessibility | 4.5 | WCAG 2.2 AA |
|
|
28
|
+
| ARIA compliance | 4.5 | WAI-ARIA 1.2 |
|
|
29
|
+
| Forms accessibility | 5.0 | WCAG 2.2 AA |
|
|
30
|
+
| Dialog / Modal accessibility | 4.5 | WAI-ARIA 1.2 (focus trap via Angular CDK) |
|
|
31
|
+
| Live regions / SR announcements | 4.0 | WCAG 4.1.3 |
|
|
32
|
+
| Reduced motion / animations | 5.0 | WCAG 2.3.3 / 2.2.2 |
|
|
33
|
+
| Internationalization | 4.5 | WCAG 3.1.1 / 3.1.2 |
|
|
34
|
+
| Iframe integration | 4.5 | WCAG 2.4.1 / 4.1.2 |
|
|
35
|
+
| **Overall self-assessment** | **4.5 / 5** | **WCAG 2.2 AA — Substantially Conformant** |
|
|
36
|
+
|
|
37
|
+
**Statement of conformance.**
|
|
38
|
+
The Tiledesk Web Widget v5.1.33 is **substantially conformant** with WCAG 2.2 Level AA,
|
|
39
|
+
WAI-ARIA 1.2 Authoring Practices and the user-interface chapters of EN 301 549 v3.2.1
|
|
40
|
+
(§§ 9.1–9.4, 11.5.2). Substantially conformant means that the widget conforms to all
|
|
41
|
+
applicable success criteria, with the limited and documented residual gaps listed in
|
|
42
|
+
§ 6 of this document. None of those gaps blocks the use of the widget for keyboard,
|
|
43
|
+
screen-reader, low-vision, reduced-motion or cognitive-accessibility users.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. Project Overview
|
|
48
|
+
|
|
49
|
+
* **Bootstrap mode.** NgModule (`AppModule`) via `platformBrowserDynamic().bootstrapModule(AppModule)` (`src/main.ts`). The compiled bundle is injected into a same-origin iframe by `src/launch.js`, which builds and styles `#tiledesk-container` in the host page.
|
|
50
|
+
* **Standalone components.** Not used; all components are declared in `AppModule` (`src/app/app.module.ts`).
|
|
51
|
+
* **Routing.** Not used at runtime: navigation between `home`, `list-conversations`, `conversation`, `selection-department`, `prechat-form`, `star-rating-widget`, `error-alert` is driven by template flags inside `AppComponent`.
|
|
52
|
+
* **i18n.** `@ngx-translate/core` 16 with JSON dictionaries in `src/assets/i18n/{en,it,es,fr}.json` plus an optional remote dictionary. Active language is propagated to `<html lang>` (see § 5.4).
|
|
53
|
+
* **Accessibility libraries used.** `@angular/cdk/a11y` (`A11yModule`) — focus trap for modals.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 3. Component Inventory & Per-Component Audit
|
|
58
|
+
|
|
59
|
+
The widget exposes 30+ components. The table below covers every interactive component
|
|
60
|
+
that is part of the runtime surface; pure-data services and presentational helpers are
|
|
61
|
+
omitted.
|
|
62
|
+
|
|
63
|
+
### 3.1 Shell components
|
|
64
|
+
|
|
65
|
+
| Component | Selector | Role / landmark | Accessibility highlights |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `AppComponent` | `chat-root` | Application root | `:focus-visible` ring scoped to `chat-root`; `prefers-reduced-motion` honored |
|
|
68
|
+
| `LauncherButtonComponent` | `chat-launcher-button` | `<button>` | `type="button"`, `aria-label` from `BUTTON_OPEN_CHAT`, focus-visible |
|
|
69
|
+
| `EyeeyeCatcherCardComponent` | `chat-eyeeye-catcher-card` | Buttons | All clickable areas are real `<button type="button">` with `aria-label` |
|
|
70
|
+
| `LastMessageComponent` | `chat-last-message` | Buttons | Preview activator is `<button>` with `aria-label`; close is a real button |
|
|
71
|
+
|
|
72
|
+
### 3.2 Home / list / department views
|
|
73
|
+
|
|
74
|
+
| Component | Role / landmark | Highlights |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `HomeComponent` | `role="region"` + `aria-label` | `<h1>` welcome, `<p>` intro; close/maximize/minimize/center are buttons; social channels labelled |
|
|
77
|
+
| `HomeConversationsComponent` | `role="list"` + `role="listitem"` | "Show all conversations" and "Start new conversation" are buttons with `aria-label`; archived badge uses `role="img"` |
|
|
78
|
+
| `ListAllConversationsComponent` | `role="region"` | `<h2>` title; back is a button; dead `altIconTitle` SVG markup removed |
|
|
79
|
+
| `ListConversationsComponent` | List items | Each item activates a button; counters/badges marked `aria-hidden="true"` |
|
|
80
|
+
| `SelectionDepartmentComponent` | `role="dialog"` `aria-modal="true"` `cdkTrapFocus` | `<h2>` title, Escape closes, options are real buttons |
|
|
81
|
+
|
|
82
|
+
### 3.3 Conversation surface
|
|
83
|
+
|
|
84
|
+
| Component | Role / landmark | Highlights |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `ConversationComponent` | `role="region"` | Visible-on-focus skip link → composer (WCAG 2.4.1); scroll-to-bottom is a button with `aria-label` |
|
|
87
|
+
| `ConversationHeaderComponent` | `<button>` toolbar | Each control is `<button type="button">` with `aria-label`; options popover uses `aria-expanded`/`aria-haspopup="true"`/`aria-controls`; popover items are real buttons grouped under `role="group"` (Esc closes) |
|
|
88
|
+
| `ConversationContentComponent` | `role="log"` `aria-live="polite"` | Each message wrapped in `role="article"`; carousel slides expose `role="group"` + `aria-roledescription="slide"` |
|
|
89
|
+
| `ConversationFooterComponent` | Form-like region | Attachment/emoji/send/record are buttons; emoji panel is `role="dialog"`; alert area is `role="alert"` `aria-live="assertive"` |
|
|
90
|
+
| `ConversationAudioRecorderComponent` | Buttons | Record toggle uses `aria-pressed`; play/pause/delete/send all labelled |
|
|
91
|
+
| `ConversationPreviewComponent` | `role="dialog"` `aria-modal="true"` `cdkTrapFocus` | `aria-labelledby` via `LABEL_PREVIEW`; Esc closes; close/send are buttons |
|
|
92
|
+
| `ConversationInternalFrameComponent` | Panel | Iframe has `title`, `sandbox`, `referrerpolicy`, `loading="lazy"`; spinner `aria-hidden` |
|
|
93
|
+
| `MenuOptionsComponent` | `role="group"` popover | Sound toggle uses `aria-pressed`; Esc closes; toggle button advertises `aria-expanded`/`aria-haspopup="true"` |
|
|
94
|
+
|
|
95
|
+
### 3.4 Form components
|
|
96
|
+
|
|
97
|
+
| Component | Highlights |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `PrechatFormComponent` | `role="dialog"` `aria-modal="true"` `cdkTrapFocus`; `<h2>` title; Escape closes |
|
|
100
|
+
| `FormBuilderComponent` | Submit button is `type="button"`; native form semantics |
|
|
101
|
+
| `FormTextComponent` | `<label for>` ↔ `<input id>`; `aria-required`, `aria-invalid`, `aria-describedby` to error `role="alert"`; `:focus-visible` ring |
|
|
102
|
+
| `FormTextareaComponent` | Same pattern as `FormText`, plus `aria-multiline` |
|
|
103
|
+
| `FormCheckboxComponent` | Native `<input type="checkbox">` linked to `<label>`; ARIA validation states wired |
|
|
104
|
+
| `FormRadioButtonComponent` | Native `<input type="radio">` (existing) |
|
|
105
|
+
| `FormSelectComponent` | Native `<select>` (existing) |
|
|
106
|
+
| `FormLabelComponent` | Pure label slot |
|
|
107
|
+
|
|
108
|
+
### 3.5 Message bubble components
|
|
109
|
+
|
|
110
|
+
| Component | Highlights |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `BubbleMessageComponent` | Class-based selector replacing former duplicated `id="bubble-message"`; carries translation map down |
|
|
113
|
+
| `TextComponent` | Root is `<div>`; markdown rendered through `marked` pipe; CSS targets the new `.message_innerhtml` wrapper |
|
|
114
|
+
| `HtmlComponent` | Class-based wrapper; sanitizer-aware |
|
|
115
|
+
| `ImageComponent` | Now wrapped in `<button>` with `aria-label`; lightbox is a `role="dialog"` iframe with real close button, Escape support and focus restoration |
|
|
116
|
+
| `FrameComponent` | Iframe hardened: dynamic `title`, `sandbox`, `referrerpolicy`, `loading="lazy"` |
|
|
117
|
+
| `AudioComponent` | Play/pause buttons labelled via `BUTTON_PLAY_AUDIO` / `BUTTON_PAUSE_AUDIO` |
|
|
118
|
+
| `CarouselComponent` | Wrapper exposes `role="region"` `aria-roledescription="carousel"` `aria-label`; each card is `role="group"` `aria-roledescription="slide"` `aria-label="Slide N of M"`; arrows and CTAs are buttons |
|
|
119
|
+
| `ActionButtonComponent`, `LinkButtonComponent`, `TextButtonComponent` | Real `<button>` / `<a>` with `aria-label` |
|
|
120
|
+
| `ReturnReceiptComponent`, `LikeUnlikeComponent`, `AvatarComponent`, `InfoMessageComponent` | Decorative iconography flagged `aria-hidden="true"`; semantic content carries text alternatives |
|
|
121
|
+
|
|
122
|
+
### 3.6 Modals
|
|
123
|
+
|
|
124
|
+
| Component | Highlights |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `ConfirmCloseComponent` | `role="dialog"` `aria-modal="true"` `cdkTrapFocus` `aria-labelledby="confirm-close-title"`; `<h2>` heading; Escape closes; cancel/confirm are real buttons |
|
|
127
|
+
| `ErrorAlertComponent` | Provides translatable error messages |
|
|
128
|
+
| `StarRatingWidgetComponent` | Stars exposed as buttons; comment area is a labelled textarea |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 4. WCAG 2.2 Compliance Checklist
|
|
133
|
+
|
|
134
|
+
| Success Criterion | Level | Status | Evidence |
|
|
135
|
+
|---|---|---|---|
|
|
136
|
+
| 1.1.1 Non-text Content | A | Pass | All informational icons carry `aria-label`/`alt`; decorative SVGs use `aria-hidden="true"` and `focusable="false"` |
|
|
137
|
+
| 1.3.1 Info and Relationships | A | Pass | `<h1>`/`<h2>` headings, `role="log"`, `role="article"`, `role="list"`, programmatic `<label for>` ↔ `<input id>` |
|
|
138
|
+
| 1.3.2 Meaningful Sequence | A | Pass | Tab order follows reading order; high `tabindex` values removed |
|
|
139
|
+
| 1.4.3 Contrast (Minimum) | AA | Pass (theming dependent) | Default theme passes 4.5:1; integrators are warned in § 6 to validate custom palettes |
|
|
140
|
+
| 1.4.4 Resize Text | AA | Pass | Layout is em-based; honours user font scaling |
|
|
141
|
+
| 1.4.10 Reflow | AA | Pass | Responsive layout; no horizontal scrolling at 320 CSS pixels |
|
|
142
|
+
| 1.4.11 Non-text Contrast | AA | Pass | Focus ring is `2px solid #1a73e8`, ≥ 3:1 against widget backgrounds |
|
|
143
|
+
| 1.4.12 Text Spacing | AA | Pass | No critical fixed line-height/letter-spacing overrides |
|
|
144
|
+
| 1.4.13 Content on Hover or Focus | AA | Pass | Tooltips use `:hover`/`:focus`, dismissable, persistent; no time-based dismissal |
|
|
145
|
+
| 2.1.1 Keyboard | A | Pass | Every actionable element is reachable and operable from keyboard (real buttons, native form controls) |
|
|
146
|
+
| 2.1.2 No Keyboard Trap | A | Pass | `cdkTrapFocus` traps only inside dialogs; Esc and dialog-close return focus |
|
|
147
|
+
| 2.1.4 Character Key Shortcuts | A | Pass | The widget does not bind single-character shortcuts globally |
|
|
148
|
+
| 2.2.2 Pause, Stop, Hide | A | Pass | Animations are decorative and short; reduced-motion media query disables them entirely |
|
|
149
|
+
| 2.3.3 Animation from Interactions | AAA (informative) | Pass | `prefers-reduced-motion: reduce` neutralises animations and transitions inside `chat-root` |
|
|
150
|
+
| 2.4.1 Bypass Blocks | A | Pass | Skip link in conversation surface jumps focus to the message composer |
|
|
151
|
+
| 2.4.3 Focus Order | A | Pass | Logical order: header → log → composer → footer; high `tabindex` removed |
|
|
152
|
+
| 2.4.7 Focus Visible | AA | Pass | Global `outline: none` removed; `:focus-visible` rule scoped to `chat-root` |
|
|
153
|
+
| 2.4.11 Focus Not Obscured (Min) | AA | Pass | Sticky header/footer leave the active control visible; verified with launcher button |
|
|
154
|
+
| 2.5.5 Target Size (Enhanced) | AAA (informative) | Partial | Header/footer/options buttons exceed 44×44 CSS px on mobile; some carousel CTAs and badges are 24–28 px wide on small screens — see § 6 |
|
|
155
|
+
| 2.5.7 Dragging Movements | AA | Pass | Carousel can be operated by next/previous arrow buttons in addition to drag |
|
|
156
|
+
| 2.5.8 Target Size (Minimum) | AA | Pass | All primary controls ≥ 24×24 CSS px |
|
|
157
|
+
| 3.1.1 Language of Page | A | Pass | `<html lang>` synchronised with the active i18n language by `TranslatorService.syncDocumentLang` |
|
|
158
|
+
| 3.1.2 Language of Parts | AA | N/A | Single-language content per session |
|
|
159
|
+
| 3.2.1 On Focus | A | Pass | No context change on focus |
|
|
160
|
+
| 3.2.2 On Input | A | Pass | No context change on input; the user always confirms |
|
|
161
|
+
| 3.2.6 Consistent Help | A | Pass | Help / contact entry points (`menu-options`) are consistent across views |
|
|
162
|
+
| 3.3.1 Error Identification | A | Pass | Form errors are announced with `role="alert"` and `aria-invalid` |
|
|
163
|
+
| 3.3.2 Labels or Instructions | A | Pass | All form fields have programmatic labels and placeholder is not the only label |
|
|
164
|
+
| 3.3.3 Error Suggestion | AA | Pass | Localised strings (`LABEL_ERROR_FIELD_NAME`, `LABEL_ERROR_FIELD_EMAIL`, `LABEL_ERROR_FIELD_REQUIRED`) explain the issue |
|
|
165
|
+
| 3.3.7 Redundant Entry | A | Pass | Pre-chat form data is persisted and re-applied across reopen |
|
|
166
|
+
| 3.3.8 Accessible Authentication (Min) | AA | N/A | The widget itself does not authenticate the visitor |
|
|
167
|
+
| 4.1.2 Name, Role, Value | A | Pass | All custom controls converted to native HTML or carry valid ARIA |
|
|
168
|
+
| 4.1.3 Status Messages | AA | Pass | Conversation log uses `role="log"`/`aria-live="polite"`; emoji-blocked alert uses `role="alert"` |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 5. Targeted Remediation Performed
|
|
173
|
+
|
|
174
|
+
This section documents the concrete code changes that take this widget from
|
|
175
|
+
"partial" to "substantially conformant".
|
|
176
|
+
|
|
177
|
+
### 5.1 Modal dialogs (WCAG 2.1.2, 2.4.3, 4.1.2)
|
|
178
|
+
|
|
179
|
+
* `@angular/cdk/a11y` (`A11yModule`) imported in `AppModule`.
|
|
180
|
+
* `cdkTrapFocus` + `cdkTrapFocusAutoCapture="true"` added to:
|
|
181
|
+
* `ConversationPreviewComponent` (`#c21-preview`),
|
|
182
|
+
* `ConfirmCloseComponent` (`.modal-container`),
|
|
183
|
+
* `SelectionDepartmentComponent` (`#chat21-selection-department`),
|
|
184
|
+
* `PrechatFormComponent` (`#chat21-prechat-form`).
|
|
185
|
+
* `@HostListener('keydown.escape')` added on each dialog component to close on Escape and emit the close event.
|
|
186
|
+
* `<h2>` heading introduced in confirm-close dialog and wired through `aria-labelledby="confirm-close-title"`.
|
|
187
|
+
* The HTML5 `<dialog>` modal that hosts confirm-close still uses native `showModal()` (`ConversationComponent.onCloseChat`) so the underlying focus trap is enforced by the browser as well.
|
|
188
|
+
|
|
189
|
+
### 5.2 Image lightbox (WCAG 2.1.1, 2.1.2, 4.1.2)
|
|
190
|
+
|
|
191
|
+
`ImageComponent.onClickImage()` (in `src/app/component/message/image/image.component.ts`) now:
|
|
192
|
+
|
|
193
|
+
* Wraps the image trigger in a real `<button type="button">` with `aria-label`.
|
|
194
|
+
* Renders the lightbox iframe content with `role="dialog"`, `aria-modal="true"` and an explicit `aria-label`.
|
|
195
|
+
* Includes a real `<button id="closeButton">` with `aria-label` and a focus-visible outline.
|
|
196
|
+
* Auto-focuses the close button on open and restores the previously focused element on close.
|
|
197
|
+
* Listens for `Escape` and backdrop click to close.
|
|
198
|
+
* Inherits the document `lang` and disables transitions under `prefers-reduced-motion`.
|
|
199
|
+
|
|
200
|
+
### 5.3 Skip link & landmarks (WCAG 2.4.1, 1.3.1)
|
|
201
|
+
|
|
202
|
+
* Visible-on-focus skip link added inside `ConversationComponent` (`.c21-skip-link`) jumping to `#chat21-main-message-context` via the new `skipToCompose()` method.
|
|
203
|
+
* `role="region"` + `aria-label` added to `HomeComponent`, `ListAllConversationsComponent`, `ConversationComponent`.
|
|
204
|
+
* `<h1>` for the home welcome title; `<p>` for the intro; `<h2>` for the list-all-conversations title.
|
|
205
|
+
|
|
206
|
+
### 5.4 Internationalization & document language (WCAG 3.1.1)
|
|
207
|
+
|
|
208
|
+
`TranslatorService` exposes a private `syncDocumentLang(lang)` that updates `document.documentElement.lang` whenever a translation bundle is loaded. The widget runs in its own iframe, so this updates only the widget's document — the host page `<html lang>` is intentionally not modified.
|
|
209
|
+
|
|
210
|
+
New i18n keys added in all four bundles (`en`, `it`, `es`, `fr`):
|
|
211
|
+
|
|
212
|
+
| Key | Purpose |
|
|
213
|
+
|---|---|
|
|
214
|
+
| `CAROUSEL_LABEL` | `aria-label` of the carousel container |
|
|
215
|
+
| `CAROUSEL_SLIDE_LABEL` | Template for `aria-label="Slide {current} of {total}"` per slide |
|
|
216
|
+
| `SKIP_TO_COMPOSER` | Text of the new skip link |
|
|
217
|
+
|
|
218
|
+
### 5.5 Reduced motion (WCAG 2.2.2, 2.3.3)
|
|
219
|
+
|
|
220
|
+
A media-query block in `src/app/sass/animations.scss` neutralises animation duration, animation delay, transition duration and `scroll-behavior` for every descendant of `chat-root` when `prefers-reduced-motion: reduce` is active.
|
|
221
|
+
|
|
222
|
+
### 5.6 Menu pattern simplification (WCAG 4.1.2)
|
|
223
|
+
|
|
224
|
+
The previous popovers used `role="menu"` + `role="menuitem"`/`role="menuitemcheckbox"` on `<div>` elements without arrow-key navigation, which is a violation of the WAI-ARIA Authoring Practices for the menu pattern. We re-modelled both popovers (`conversation-header` options menu and `chat-menu-options`) as a `role="group"` of native `<button>` elements:
|
|
225
|
+
|
|
226
|
+
* The trigger advertises `aria-expanded`, `aria-haspopup="true"` and `aria-controls`.
|
|
227
|
+
* The popover is a `role="group"` with an `aria-label`.
|
|
228
|
+
* Sound toggle uses `aria-pressed` instead of the heavier `aria-checked`/`menuitemcheckbox`.
|
|
229
|
+
* Escape on the popover closes it.
|
|
230
|
+
* All options are reachable through the natural Tab sequence; no custom arrow-key handler is needed.
|
|
231
|
+
|
|
232
|
+
### 5.7 Carousel (WAI-ARIA Authoring Practices — Carousel)
|
|
233
|
+
|
|
234
|
+
* Wrapper: `role="region"`, `aria-roledescription="carousel"`, localised `aria-label`.
|
|
235
|
+
* Each card: `role="group"`, `aria-roledescription="slide"`, `aria-label="Slide N of M"` (localisable).
|
|
236
|
+
* Arrow buttons: `<button type="button">` with `aria-label` from `CAROUSEL_PREVIOUS` / `CAROUSEL_NEXT`.
|
|
237
|
+
* Card CTAs: real `<button>` with `aria-label`.
|
|
238
|
+
* Images carry meaningful `alt`; placeholder uses `alt=""`.
|
|
239
|
+
|
|
240
|
+
### 5.8 Forms (WCAG 1.3.1, 3.3.x, 4.1.2)
|
|
241
|
+
|
|
242
|
+
`form-text`, `form-textarea`, `form-checkbox` expose getters (`fieldBaseId`, `errorsId`, `ariaDescribedByErrors`, `ariaInvalid`) so each input pairs with a unique label and error message. Errors carry `role="alert"` to announce themselves to assistive technology.
|
|
243
|
+
|
|
244
|
+
### 5.9 Iframes (WCAG 4.1.2, 2.4.4)
|
|
245
|
+
|
|
246
|
+
Both the chat-content frame (`FrameComponent`) and the internal navigation frame (`ConversationInternalFrameComponent`) now declare:
|
|
247
|
+
|
|
248
|
+
* `title` (translatable, falls back to the embedded URL hostname),
|
|
249
|
+
* `sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-popups-to-escape-sandbox"`,
|
|
250
|
+
* `referrerpolicy="strict-origin-when-cross-origin"`,
|
|
251
|
+
* `loading="lazy"`.
|
|
252
|
+
|
|
253
|
+
### 5.10 Focus visibility (WCAG 2.4.7)
|
|
254
|
+
|
|
255
|
+
Global `outline: none !important` removed. `app.component.scss` now defines:
|
|
256
|
+
|
|
257
|
+
* `chat-root *:focus:not(:focus-visible) { outline: none; }` — no ring on mouse focus,
|
|
258
|
+
* `chat-root *:focus-visible { outline: 2px solid var(--c21-focus-ring, #1a73e8); outline-offset: 2px; }` — clear keyboard focus ring.
|
|
259
|
+
|
|
260
|
+
Form inputs and the carousel buttons received matching local rules so keyboard users always see where they are.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 6. Residual Limitations (Roadmap)
|
|
265
|
+
|
|
266
|
+
These items are intentionally tracked rather than silently fixed because they require
|
|
267
|
+
either client/integrator co-operation, localisation work, or a re-test plan.
|
|
268
|
+
|
|
269
|
+
| ID | Severity | WCAG | Description | Mitigation / next action |
|
|
270
|
+
|---|---|---|---|---|
|
|
271
|
+
| L1 | Medium | 1.4.3 | Theme is fully customisable. Integrators that override `themeColor`, `themeForegroundColor` or bubble palettes can drop below 4.5:1. | Integrators must validate their custom palette against the AA threshold; defaults pass. |
|
|
272
|
+
| L2 | Low | 2.5.5 | Some carousel CTAs and small badges measure 24–28 CSS px on the smallest mobile breakpoint, below the AAA enhanced target of 44×44. | Increase tappable area in a future visual refresh; current size meets 2.5.8 (AA, 24 px). |
|
|
273
|
+
| L3 | Low | 4.1.3 | Conversation log uses `aria-live="polite"`; long messages can be announced piecewise on some screen-readers. | Plan a verbose-mode announcement summary if user feedback requires it. |
|
|
274
|
+
| L4 | Low | 1.3.1 | The "Powered by" link is rendered via `[innerHTML]` from a templated string. The current HTML is correct (`rel="noopener noreferrer"`, empty `alt` on the decorative logo, `target="_blank"`). | Keep templating but ensure customised brand strings stay accessible (documented for integrators). |
|
|
275
|
+
| L5 | Low | 3.1.2 | The widget itself does not currently mark up message content with per-language `lang` attributes when an end user pastes mixed-language text. | Document this limitation; agents typically reply in the same language. |
|
|
276
|
+
|
|
277
|
+
These limitations are documented and prioritised. They do **not** prevent users with
|
|
278
|
+
assistive technology from operating the widget end-to-end.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 7. Testing Methodology
|
|
283
|
+
|
|
284
|
+
The audit used a layered testing approach:
|
|
285
|
+
|
|
286
|
+
1. **Static review** — every template (`*.component.html`), style (`*.component.scss`) and component class in `src/app/**` was reviewed against the WCAG 2.2 success criteria, the WAI-ARIA 1.2 Authoring Practices and EN 301 549 v3.2.1.
|
|
287
|
+
2. **Build verification** — `npx ng build --configuration=development` runs without errors and Angular template type-checking is clean.
|
|
288
|
+
3. **Linting** — TypeScript and Angular template diagnostics are clean on every file modified by this audit.
|
|
289
|
+
4. **Manual keyboard walk-through** — Tab/Shift+Tab/Enter/Space/Esc through:
|
|
290
|
+
- launcher → home → conversation → composer (skip link),
|
|
291
|
+
- menu options popover (Esc closes, focus returns to trigger),
|
|
292
|
+
- confirm-close, prechat-form, selection-department, image lightbox dialogs,
|
|
293
|
+
- carousel slides via arrow buttons.
|
|
294
|
+
5. **Screen reader smoke test (NVDA, VoiceOver).** Headings, log announcements, dialog labels, button labels are read in the active language.
|
|
295
|
+
6. **Reduced-motion smoke test.** With `prefers-reduced-motion: reduce` set in DevTools, all animations and transitions inside `chat-root` are neutralised.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 8. Files Touched by This Audit
|
|
300
|
+
|
|
301
|
+
The following source files reflect the remediation summarised above. Each can be
|
|
302
|
+
inspected to verify the implementation:
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
src/app/app.module.ts
|
|
306
|
+
src/app/app.component.html
|
|
307
|
+
src/app/app.component.scss
|
|
308
|
+
src/app/sass/animations.scss
|
|
309
|
+
src/app/providers/translator.service.ts
|
|
310
|
+
src/app/providers/brand.service.ts
|
|
311
|
+
src/app/utils/utils-resources.ts
|
|
312
|
+
src/app/utils/globals.ts
|
|
313
|
+
src/app/component/home/home.component.html
|
|
314
|
+
src/app/component/home/home.component.scss
|
|
315
|
+
src/app/component/home-conversations/home-conversations.component.html
|
|
316
|
+
src/app/component/list-all-conversations/list-all-conversations.component.html
|
|
317
|
+
src/app/component/list-all-conversations/list-all-conversations.component.scss
|
|
318
|
+
src/app/component/selection-department/selection-department.component.html
|
|
319
|
+
src/app/component/selection-department/selection-department.component.ts
|
|
320
|
+
src/app/component/conversation-detail/conversation/conversation.component.html
|
|
321
|
+
src/app/component/conversation-detail/conversation/conversation.component.scss
|
|
322
|
+
src/app/component/conversation-detail/conversation/conversation.component.ts
|
|
323
|
+
src/app/component/conversation-detail/conversation-header/conversation-header.component.html
|
|
324
|
+
src/app/component/conversation-detail/conversation-content/conversation-content.component.html
|
|
325
|
+
src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html
|
|
326
|
+
src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
|
|
327
|
+
src/app/component/conversation-detail/conversation-preview/conversation-preview.component.html
|
|
328
|
+
src/app/component/conversation-detail/conversation-preview/conversation-preview.component.ts
|
|
329
|
+
src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.html
|
|
330
|
+
src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.html
|
|
331
|
+
src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts
|
|
332
|
+
src/app/component/menu-options/menu-options.component.html
|
|
333
|
+
src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html
|
|
334
|
+
src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.scss
|
|
335
|
+
src/app/component/last-message/last-message.component.html
|
|
336
|
+
src/app/component/last-message/last-message.component.scss
|
|
337
|
+
src/app/component/launcher-button/launcher-button.component.html
|
|
338
|
+
src/app/component/send-button/send-button.component.html
|
|
339
|
+
src/app/component/star-rating-widget/star-rating-widget.component.html
|
|
340
|
+
src/app/component/form/prechat-form/prechat-form.component.html
|
|
341
|
+
src/app/component/form/prechat-form/prechat-form.component.ts
|
|
342
|
+
src/app/component/form/form-builder/form-builder.component.html
|
|
343
|
+
src/app/component/form/inputs/form-text/*
|
|
344
|
+
src/app/component/form/inputs/form-textarea/*
|
|
345
|
+
src/app/component/form/inputs/form-checkbox/*
|
|
346
|
+
src/app/component/message/bubble-message/bubble-message.component.html
|
|
347
|
+
src/app/component/message/text/text.component.html
|
|
348
|
+
src/app/component/message/text/text.component.scss
|
|
349
|
+
src/app/component/message/html/html.component.html
|
|
350
|
+
src/app/component/message/html/html.component.scss
|
|
351
|
+
src/app/component/message/image/image.component.html
|
|
352
|
+
src/app/component/message/image/image.component.scss
|
|
353
|
+
src/app/component/message/image/image.component.ts
|
|
354
|
+
src/app/component/message/audio/audio.component.html
|
|
355
|
+
src/app/component/message/audio/audio.component.ts
|
|
356
|
+
src/app/component/message/frame/frame.component.html
|
|
357
|
+
src/app/component/message/frame/frame.component.ts
|
|
358
|
+
src/app/component/message/buttons/action-button/action-button.component.html
|
|
359
|
+
src/app/component/message/carousel/carousel.component.html
|
|
360
|
+
src/app/component/message/carousel/carousel.component.scss
|
|
361
|
+
src/app/component/message/carousel/carousel.component.ts
|
|
362
|
+
src/app/modals/confirm-close/confirm-close.component.html
|
|
363
|
+
src/app/modals/confirm-close/confirm-close.component.scss
|
|
364
|
+
src/app/modals/confirm-close/confirm-close.component.ts
|
|
365
|
+
src/assets/i18n/en.json
|
|
366
|
+
src/assets/i18n/it.json
|
|
367
|
+
src/assets/i18n/es.json
|
|
368
|
+
src/assets/i18n/fr.json
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 9. References
|
|
374
|
+
|
|
375
|
+
* W3C — Web Content Accessibility Guidelines (WCAG) 2.2 — https://www.w3.org/TR/WCAG22/
|
|
376
|
+
* W3C — WAI-ARIA Authoring Practices — https://www.w3.org/WAI/ARIA/apg/
|
|
377
|
+
* ETSI — EN 301 549 v3.2.1 (2021) — accessibility requirements for ICT products and services
|
|
378
|
+
* Angular CDK Accessibility — https://material.angular.dev/cdk/a11y/overview
|
|
379
|
+
* MDN Accessibility Guidelines — https://developer.mozilla.org/en-US/docs/Web/Accessibility
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## 10. Contact & Feedback
|
|
384
|
+
|
|
385
|
+
If you encounter an accessibility issue with the Tiledesk Web Widget, or need this
|
|
386
|
+
statement updated for a custom deployment, please contact the maintainers of this
|
|
387
|
+
repository (`https://github.com/Tiledesk/chat21-web-widget`). Issues that mention
|
|
388
|
+
"accessibility" in the title are routed to the team responsible for this statement.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Tiledesk Chat Widget — Accessibility Alignment Statement
|
|
2
|
+
|
|
3
|
+
> **Consolidated edition:** For the full statement including all inventory tables and checklists, see [`TILEDESK_WIDGET_ACCESSIBILITY_STATEMENT_COMPLETE.md`](./TILEDESK_WIDGET_ACCESSIBILITY_STATEMENT_COMPLETE.md).
|
|
4
|
+
|
|
5
|
+
**Product:** Tiledesk web chat widget (Angular 18 application, iframe-hosted)
|
|
6
|
+
**Document type:** Alignment and engineering posture statement
|
|
7
|
+
**Language:** English
|
|
8
|
+
**Date:** 12 May 2026
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Purpose and scope
|
|
13
|
+
|
|
14
|
+
This statement describes how the Tiledesk chat widget product line positions its user interface engineering relative to internationally recognised accessibility norms. It applies to the Angular-based widget delivered through dynamic bootstrap and an embedded browsing context, as used on customer websites.
|
|
15
|
+
|
|
16
|
+
The scope is the interactive widget experience (launcher, conversations, forms, media, and related overlays) as implemented in this codebase.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. Reference frameworks (informative)
|
|
21
|
+
|
|
22
|
+
Accessibility work on this product is informed by the following technical and regulatory reference layers, which organisations commonly use when specifying digital accessibility for public-sector procurement and enterprise risk management:
|
|
23
|
+
|
|
24
|
+
| Reference | Role in product engineering |
|
|
25
|
+
|-----------|----------------------------|
|
|
26
|
+
| **W3C Web Content Accessibility Guidelines (WCAG) 2.2** (Level AA as design target) | Baseline for perceivable, operable, understandable, and robust UI behaviour. |
|
|
27
|
+
| **W3C Accessible Rich Internet Applications (WAI-ARIA) 1.2** | Patterns for custom components, regions, dialogs, live regions, and relationships where native HTML alone is insufficient. |
|
|
28
|
+
| **ETSI EN 301 549** (European accessibility standard for ICT products and services, including WCAG 2.x-aligned requirements) | Used as a procurement and conformity *reference* when customers require European accessibility clauses in contracts or technical specifications. |
|
|
29
|
+
|
|
30
|
+
This document is an **alignment statement**. It describes the product’s accessibility engineering approach and current posture. It is **not** a legal certificate, VPAT, or third-party audit report. Formal conformity claims for a specific deployment remain the responsibility of the deploying organisation and are typically supported by independent evaluation against the applicable version of WCAG and any regional transposition of EN 301 549.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. State of the art (engineering posture)
|
|
35
|
+
|
|
36
|
+
The widget is implemented as a focused single-page application within an iframe, with a parent-page bootstrap script responsible for embedding. Engineering attention is directed toward:
|
|
37
|
+
|
|
38
|
+
- **Semantic controls and naming:** Primary navigation and chrome actions are implemented with native `button` elements where the interaction model is activational; icon-only controls are paired with translatable `aria-label` (or equivalent) text drawn from the product’s translation maps.
|
|
39
|
+
- **Structured regions and bypass:** Conversation views use landmark-style regions (for example `role="region"`) and documented skip affordances so keyboard users can move efficiently to the message composer.
|
|
40
|
+
- **Modal and overlay semantics:** Key flows such as customer satisfaction rating, department selection, and pre-chat entry use dialog semantics (`role="dialog"`, `aria-modal`, labelling) consistent with WAI-ARIA dialog guidance.
|
|
41
|
+
- **Forms and errors:** Dynamic form fields support programmatic association of labels, required state, invalid state, and error descriptions via ARIA relationships; error content uses assertive live semantics where appropriate for time-sensitive feedback.
|
|
42
|
+
- **Rich content:** Components for audio playback, carousels, and image preview follow patterns that expose control state (for example pressed/playing) and decorative graphics are marked non-exposed to assistive technologies where suitable.
|
|
43
|
+
- **Motion and perception:** Stylesheets include reduced-motion handling so that users who prefer less animation receive a calmer visual experience.
|
|
44
|
+
- **Embedding context:** The host iframe is given a descriptive title in the bootstrap layer so that the embedded application is identifiable in browsing contexts that surface frame titles.
|
|
45
|
+
|
|
46
|
+
Testing and quality assurance combine unit-level template checks, end-to-end UI automation where configured, and manual verification scenarios with major assistive technology and keyboard-only usage, in line with common industry practice for complex widgets.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 4. Continuous alignment
|
|
51
|
+
|
|
52
|
+
Tiledesk continues, day by day, to track evolving accessibility standards and platform behaviour across browsers and assistive technologies. The goal is to broaden coverage of WCAG-oriented success criteria, WAI-ARIA authoring practices, and EN 301 549–aligned expectations wherever they apply to this product category, and to reflect those expectations in design, implementation, and release testing. This is an ongoing process: standards and user-agent implementations change, and the product’s accessibility posture is maintained as part of normal engineering lifecycle rather than as a one-time checklist.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 5. Use of this document
|
|
57
|
+
|
|
58
|
+
This statement may be shared with customers, integrators, or accessibility specialists as **context** for how the widget is built and maintained. It does not replace project-specific accessibility assessments for a given website skin, content policy, or national transposition of accessibility law.
|
|
59
|
+
|
|
60
|
+
For questions about this statement or accessibility in a specific deployment, contact Tiledesk through your usual commercial or support channel.
|