text-base-content/60 (~4.1:1 against base-100) fails the 4.5:1 AA minimum
for normal-weight text. Change inactive tab to text-base-content (full
opacity, ~14:1) so contrast is unambiguously compliant. Visual distinction
between active/inactive now relies on the colored border underline + primary
text color, not opacity dimming. Hover updated to hover:text-primary to
preview the tab's active color before clicking.
Affects: submissions/show, submit_form/show, document_tabs.js, document.vue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Analyzed whether emitting Markdown as an intermediate format would improve
lib/pdf_text_to_html.rb and app/javascript/template_builder/pdf_text_to_html.js.
Decision: no change warranted. Key reasons: no full Markdown gem on Ruby side,
snarkdown is inline-only (no block elements), dir="auto" RTL support can't be
expressed in Markdown, and PDF text contains raw * _ # characters that would
corrupt Markdown rendering.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create pdf_text_to_html.js: JS port of the Ruby heuristic parser
(ALL_CAPS→h2, numbered headings→h3, bullets→ul/li, body→p dir=auto)
- Add pdf_view, text_view, document_view_options keys to i18n.js (en)
- Update document.vue: tab switcher shown when all pages have extracted
text; PDF View renders the existing page images; Text View renders
heuristic HTML in a prose container with per-page sections
- ArrowLeft/ArrowRight keyboard navigation between tabs with focus management
- Tab is hidden entirely for scanned/image-only PDFs (hasFullText gate)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The page.vue component uses container-type: size for CSS container
queries. This containment context interferes with the clip: rect(0,0,0,0)
technique used by Tailwind's sr-only class, causing the hidden page text
to render visually below the PDF image.
Replace sr-only class with position: absolute; left: -9999px off-screen
technique which is robust against CSS containment contexts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create PdfTextToHtml heuristic parser (ALL_CAPS→h2, numbered→h3, bullets→ul, body→p)
- Create document-tabs custom element (ARIA APG tab pattern, roving tabindex, localStorage persistence)
- Register document-tabs element in application.js
- Add tab switcher to submissions/show and submit_form/show when all pages have extracted text
- Add text panel with per-page sections to both views
- Fix role="region" bug on sr-only page text divs (excess ARIA landmarks)
- Add 5 new i18n keys: pdf_view, text_view, document_view_options, text_view_disclaimer, signing_fields_below
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents the accessibility specialist review of the proposed tab
switcher feature: ARIA tablist/tab/tabpanel pattern requirements,
heuristic HTML parsing strategy for extracted text, signing form
UX recommendation (read-only text view + always-visible Vue panel),
and concrete pitfalls including DaisyUI incompatibility with APG
keyboard model, 15-page cap handling, and RTL text direction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts PDF text during upload via Pdfium and stores it in attachment
metadata (pdf.pages_text), then surfaces it in visually-hidden sr-only
regions in both the signing form and submission preview views. Also adds
alt text to template builder page images and ARIA role/label to the
page-container custom element.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added new gems: axe-core-api, axe-core-rspec, axiom-types, coercible, descendants_tracker, dumb_delegator, and virtus for enhanced accessibility and data handling.
- Updated database schema comments for clarity, ensuring proper formatting for index definitions in document_generation_event.rb, email_event.rb, lock_event.rb, submission_event.rb, and submission.rb.
- Adjusted the schema version in db/schema.rb to reflect the latest changes.
These updates contribute to ongoing accessibility improvements and maintain code clarity.
Three translation keys added as part of a11y accessibility work
were missing from the locale file:
- preview_of: used in submissions/show.html.erb img alt text
- your_signature: used in profile/index.html.erb img alt text
- your_initials: used in profile/index.html.erb img alt text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The submit_form/show.html.erb uses t('page') and t('of') to build
accessible alt text for document page images (e.g. "Page 1 of Contract").
These keys were added as part of a11y work but never added to the locale file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The _navbar.html.erb aria-label uses t('user_menu') but the key was
never added to the locale file, causing a MissingTranslationData error
in development.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Completed Tasks 5 and 6:
- Task 5: Added ARIA labels to 12 icon-only buttons
- Task 6: Added keyboard support to 3 custom web components
Phase 1 Status:
- 6 of 7 tasks completed (86%)
- Only Task 7 (testing) remains, blocked by Ruby version requirement
- 5 WCAG 2.2 Level A criteria now satisfied
WCAG Compliance Progress:
✅ 1.1.1 Non-text Content (Level A)
✅ 1.3.1 Info and Relationships (Level A)
✅ 2.1.1 Keyboard (Level A) - NEW
✅ 2.4.1 Bypass Blocks (Level A)
✅ 4.1.2 Name, Role, Value (Level A) - NEW
Next: Resolve Ruby blocker and complete automated testing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added Enter and Space key handlers to 3 custom elements for full keyboard accessibility:
1. clipboard_copy.js:
- Added keydown listener for Enter/Space keys
- Set tabindex="0" and role="button" for keyboard focus
- Refactored click handler into reusable copyToClipboard function
- Keyboard users can now copy text without a mouse
2. download_button.js:
- Added keydown listener for Enter/Space keys
- Set tabindex="0" and role="button" for keyboard focus
- Keyboard users can now trigger file downloads
3. password_input.js:
- Added keydown listener to togglePasswordVisibility element
- Set tabindex="0" and role="button" on toggle button
- Properly cleanup event listener in disconnectedCallback
- Keyboard users can now toggle password visibility
All implementations:
- Use e.preventDefault() to prevent default Space key scrolling
- Check for existing tabindex/role attributes before setting
- Follow WCAG 2.1.1 (Keyboard, Level A) guidelines
- Support both Enter and Space keys per ARIA authoring practices
This satisfies WCAG 2.2 Success Criterion 2.1.1 (Keyboard, Level A).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed 6 images missing alt attributes across submission form components:
- signature_step.vue: Added dynamic alt text with field name and "preview"
- initials_step.vue: Added dynamic alt text with field name and "preview"
- image_step.vue: Added dynamic alt text with field name and "preview"
- area.vue: Added alt text for 5 different image types:
* Image field
* Stamp field
* Knowledge-based authentication (KBA) field
* Signature field
* Initials field
All alt text uses field.name when available, falling back to descriptive defaults.
This satisfies WCAG 2.2 Success Criterion 1.1.1 (Non-text Content, Level A).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit establishes the foundation for WCAG 2.2 Level AA compliance:
Infrastructure:
- Add axe-core-rspec gem for automated accessibility testing
- Create spec/accessibility/ directory structure
- Add accessibility_helpers.rb with custom WCAG test helpers
- Add comprehensive testing documentation (README.md, SETUP_NOTES.md)
Semantic Landmarks (WCAG 2.4.1):
- Add <main> landmark with id="main-content" to application layout
- Add <nav> landmark with aria-label to navbar
- Add skip navigation link for keyboard users
- Skip link uses focus:translate-y-0 to appear only on keyboard focus
These changes address critical barriers for screen reader and keyboard users.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This file provides guidance for Claude Code when working in this repository,
including:
- Development commands for testing, linting, and database management
- Architecture overview of Rails backend and Vue frontend
- Testing structure with RSpec, Capybara, and Cuprite
- Deployment configurations for Docker and cloud platforms
- Key libraries, patterns, and conventions
- Multitenant support and environment configuration
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>