From 60f09745dc68644ad617ae11ca3f2539cca62bf5 Mon Sep 17 00:00:00 2001
From: Marcelo Paiva
Date: Wed, 25 Feb 2026 16:38:25 -0500
Subject: [PATCH] Fix WCAG 2.1 AA medium issues: color-only indicators, form
errors, icon-only buttons
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- M1: submissions/show.html.erb — aria-hidden on decorative color dot; sr-only text on
colored field overlays (field name + submitter) for screen reader users (WCAG 1.4.1)
- M2: field_submitter.vue — aria-hidden on all decorative color dots; aria-label on
compact mode label (selectedSubmitter name); changed inner button to span (WCAG 1.4.1)
- M8: profile/index.html.erb — inline validation error messages (role="alert") with
aria-describedby + aria-invalid on all profile and password form fields (WCAG 3.3.1)
- M10: Add aria-label to icon-only buttons/links across 7 files:
- field.vue: draw, formula, condition, settings, remove, draw-option buttons
- preview.vue: document condition and reorder buttons
- signature_step.vue: QR toggle (with aria-pressed) and close QR buttons
- text_step.vue: toggle multiline text button
- import_list.vue: preview column data info button
- Add i18n keys: show_qr_code, close_qr_code (submission_form); preview_column_data (template_builder)
Co-Authored-By: Claude Sonnet 4.6
---
app/javascript/submission_form/i18n.js | 4 +-
.../submission_form/signature_step.vue | 3 ++
app/javascript/submission_form/text_step.vue | 1 +
app/javascript/template_builder/field.vue | 6 +++
.../template_builder/field_submitter.vue | 8 +++-
app/javascript/template_builder/i18n.js | 1 +
.../template_builder/import_list.vue | 1 +
app/javascript/template_builder/preview.vue | 2 +
app/views/profile/index.html.erb | 46 +++++++++++++++----
app/views/submissions/show.html.erb | 5 +-
10 files changed, 65 insertions(+), 12 deletions(-)
diff --git a/app/javascript/submission_form/i18n.js b/app/javascript/submission_form/i18n.js
index 9bb56836..09183345 100644
--- a/app/javascript/submission_form/i18n.js
+++ b/app/javascript/submission_form/i18n.js
@@ -100,7 +100,9 @@ const en = {
wait_countdown_seconds: 'Wait {countdown} seconds',
signature_drawing_pad: 'Signature drawing pad. Use the tools above to draw or type your signature.',
initials_drawing_pad: 'Initials drawing pad. Use the tools above to draw or type your initials.',
- qr_code_for_mobile_signature: 'QR code for signing on a mobile device.'
+ qr_code_for_mobile_signature: 'QR code for signing on a mobile device.',
+ show_qr_code: 'Show QR code for mobile signing',
+ close_qr_code: 'Close QR code'
}
const es = {
diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue
index 092e6c0c..c9b4d766 100644
--- a/app/javascript/submission_form/signature_step.vue
+++ b/app/javascript/submission_form/signature_step.vue
@@ -93,6 +93,8 @@
href="#"
class="btn btn-sm btn-neutral font-medium hidden md:flex"
:class="{ 'btn-outline': !isShowQr, 'text-white': isShowQr }"
+ :aria-label="isShowQr ? t('close_qr_code') : t('show_qr_code')"
+ :aria-pressed="isShowQr ? 'true' : 'false'"
@click.prevent="isShowQr ? hideQr() : [isTextSignature = false, showQr()]"
>
diff --git a/app/javascript/submission_form/text_step.vue b/app/javascript/submission_form/text_step.vue
index 17b921c1..e6e581c0 100644
--- a/app/javascript/submission_form/text_step.vue
+++ b/app/javascript/submission_form/text_step.vue
@@ -68,6 +68,7 @@
diff --git a/app/javascript/template_builder/field.vue b/app/javascript/template_builder/field.vue
index d7e04166..a6bbb558 100644
--- a/app/javascript/template_builder/field.vue
+++ b/app/javascript/template_builder/field.vue
@@ -59,6 +59,7 @@
<%= form_for current_user, url: update_password_settings_profile_index_path, method: :patch, html: { autocomplete: 'off' } do |f| %>
<%= f.label :password, t('new_password'), class: 'label' %>
- <%= f.password_field :password, autocomplete: 'off', class: 'base-input peer w-full', required: true %>
+ <%= f.password_field :password, autocomplete: 'off', class: 'base-input peer w-full', required: true,
+ 'aria-describedby': (f.object.errors[:password].any? ? 'profile_password_error' : nil),
+ 'aria-invalid': (f.object.errors[:password].any? ? 'true' : nil) %>
+ <% if f.object.errors[:password].any? %>
+ <%= f.object.errors[:password].first %>
+ <% end %>