HIGH PRIORITY — Icon-only buttons with no accessible name:
- _toggle_view.html.erb: aria-label on Templates/Submissions view buttons
- _template.html.erb: aria-label on move, restore, edit, clone, archive/delete
(also fixes bug: was aria_label: t('restore') for all, now dynamic)
- _title.html.erb: aria-label on move-folder pencil link
- submissions/show.html.erb: aria-label on download options dropdown toggle,
audit log link, event log link, edit submitter pencil in parties view
- submit_form/show.html.erb: aria-label on scroll decline button (mobile icon-only)
- contenteditable.vue: span→role=button + aria-label + keyboard handlers (Enter/Space)
on edit pencil; aria-hidden on decorative icon
- signature_step.vue: aria-label + aria-hidden on minimize link
MEDIUM PRIORITY — Form inputs with missing labels:
- text_step.vue: conditional aria-label fallback on input/textarea when no
visible label rendered (showFieldNames=false or field has no name)
- area.vue: aria-label on multiple-select checkbox (matches radio pattern)
MEDIUM PRIORITY — Images with generic hardcoded alt text:
- area.vue: replace 'Image'/'Stamp'/'Knowledge-based authentication' with
t('image')/t('stamp')/t('kba') for i18n consistency
MEDIUM PRIORITY — Dropdown/menu ARIA:
- _navbar.html.erb: aria-controls="user-menu-list" on user menu trigger;
id="user-menu-list" on menu <ul>
MEDIUM PRIORITY — Form grouping:
- storage_settings/index.html.erb: wrap radio buttons in <fieldset><legend>
LOW PRIORITY — Required field indicator:
- mobile_fields.vue: replace tooltip span with <abbr title="required"> pattern
LOW PRIORITY — Keyboard accessibility:
- templates_folders/edit.html.erb: tabindex="0" on folder toggle label
i18n: add download_options key
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All focusable elements in the submission card now announce document
status, submitter identity, and action context to screen readers:
Status badges: "Awaiting – mpaiva+test@clearcompany.com"
Name links: "mpaiva+test@clearcompany.com – Awaiting"
Edit (icon): "Edit mpaiva+test@clearcompany.com"
Sign Now: "Sign Now – mpaiva+test@clearcompany.com"
View: "View – mpaiva+test@clearcompany.com"
Archive: "Archive – mpaiva+test@clearcompany.com"
Overlay link (invisible full-row cover) marked aria-hidden + tabindex=-1
to eliminate the duplicate focus stop and keyboard trap.
Applies to both single-submitter and multi-submitter row variants.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All buttons now include the template name for context so screen reader
users know which template they are acting on:
- Preferences (icon-only): aria-label added - was completely unlabelled
- Link, Archive, Clone, Edit, Preview, Restore: aria-label adds template
name (e.g. "Edit - NDA-accessible")
- Inner icon/text spans marked aria-hidden to prevent double-announcement
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The label element used as the upload trigger had no tabindex, making it
unreachable by keyboard. Add tabindex="0" and role="button" so it is
included in Tab order and correctly announced by screen readers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Audit found 10 overrides across 8 files that suppressed or replaced
the global focus ring. Removed all of them:
- templates/_file_form.html.erb: remove outline-none + focus:ring-*
- templates_clone/_form.html.erb: same
- templates_preferences/_recipients.html.erb: same
- template_builder/contenteditable.vue: remove outline-none
- template_builder/document.vue: remove focus:ring-2 from tab buttons
- template_builder/area.vue: remove focus:ring-1 from 3 elements
- template_builder/font_modal.vue: remove focus:ring-2 from contenteditable
- submission_form/phone_step.vue: remove focus-within:outline from container
All interactive elements now rely solely on the global :focus-visible
rule (8px solid rgb(14,99,200), 4px offset) in application.scss/form.scss.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- C1: Remove maximum-scale/user-scalable=no from viewport meta (WCAG 1.4.4)
- C2: Restore focus indicators on 7 inputs — replace outline-none/ring-0 with ring (WCAG 2.4.7)
- C3: Add focus trap + dialog role to turbo_modal.js; focus on open, restore on close (WCAG 2.4.3, 2.1.2)
- C4/C6: Replace all alert()/prompt() with ARIA live regions and custom password dialog (WCAG 3.3.1, 4.1.3)
- C5: Add aria-label to signature text input, signing reason select, checkbox and radio in area.vue (WCAG 1.3.1, 4.1.2)
- C7: Replace text-gray-100 → text-white on dark code blocks in _embedding.html.erb (WCAG 1.4.3)
- H1: Change submission name div → h1 in submit_form/show.html.erb (WCAG 2.4.6)
- H2: form.html.erb already has lang attr (confirmed correct)
- H3: Add skip link to form.html.erb layout (WCAG 2.4.1)
- H4: Replace text-gray-300/400 → text-gray-600 on light backgrounds across 5 files (WCAG 1.4.3)
- H5: Replace <a> close buttons → <button> in turbo_modal partials (WCAG 4.1.2)
- H6: Fix duplicate id="decline_button" → header/scroll variants (WCAG 4.1.1)
- L10: Add role="button" tabindex="0" to html_modal label close (WCAG 4.1.2)
- Add shared aria_announce.js utility for assertive/polite live region announcements
- Add aria-labelledby to turbo modal dialog with per-instance IDs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>