Add descriptive aria-labels to submission row focusable elements

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>
pull/599/head
Marcelo Paiva 3 weeks ago
parent 908a296a45
commit 7cfbf3a043

@ -41,19 +41,19 @@
</span> </span>
</div> </div>
<% else %> <% else %>
<a href="<%= submission_path(submission) %>" class="flex z-[1]"> <a href="<%= submission_path(submission) %>" class="flex z-[1]" aria-label="<%= "#{t(submitter.status)} #{submitter.name || submitter.email || submitter.phone}" %>">
<span class="badge <%= status_badges[submitter.status] %> md:w-32 badge-lg bg-opacity-50 uppercase text-sm font-semibold tooltip" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>"> <span class="badge <%= status_badges[submitter.status] %> md:w-32 badge-lg bg-opacity-50 uppercase text-sm font-semibold tooltip" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>">
<%= t(submitter.status) %> <%= t(submitter.status) %>
</span> </span>
</a> </a>
<% end %> <% end %>
<span class="flex items-center z-[1]"> <span class="flex items-center z-[1]">
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer"> <a href="<%= submission_path(submission) %>" class="text-lg break-all peer" aria-label="<%= "#{submitter.name || submitter.email || submitter.phone} #{t(submitter.status)}" %>">
<%= submitter.name || submitter.email || submitter.phone %> <%= submitter.name || submitter.email || submitter.phone %>
</a> </a>
<% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %> <% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>"> <span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %> <%= link_to edit_submitter_path(submitter), class: 'shrink-0', aria: { label: "#{t('edit')} #{submitter.name || submitter.email || submitter.phone}" }, data: { turbo_frame: 'modal' } do %>
<%= svg_icon('pencil', class: 'w-5 h-5') %> <%= svg_icon('pencil', class: 'w-5 h-5') %>
<% end %> <% end %>
</span> </span>
@ -81,7 +81,7 @@
<% elsif !submission.archived_at? && !template&.archived_at? && !submission.expired? && !submitter.declined_at? %> <% elsif !submission.archived_at? && !template&.archived_at? && !submission.expired? && !submitter.declined_at? %>
<% if current_user.email == submitter.email %> <% if current_user.email == submitter.email %>
<div class="flex-1 md:flex-none md:w-36 flex"> <div class="flex-1 md:flex-none md:w-36 flex">
<a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="btn btn-sm btn-neutral btn-outline bg-white w-full md:w-36 flex z-[1]"> <a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="btn btn-sm btn-neutral btn-outline bg-white w-full md:w-36 flex z-[1]" aria-label="<%= "#{t('sign_now')} #{submitter.name || submitter.email || submitter.phone}" %>">
<span class="flex items-center justify-center space-x-1 md:space-x-2"> <span class="flex items-center justify-center space-x-1 md:space-x-2">
<% if t('sign_now').length < 12 %> <% if t('sign_now').length < 12 %>
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %> <%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
@ -97,13 +97,13 @@
<% end %> <% end %>
<% end %> <% end %>
<div class="flex-1 md:flex-none z-[1]"> <div class="flex-1 md:flex-none z-[1]">
<a href="<%= submission_path(submission) %>" class="btn btn-outline btn-sm w-full md:w-24"> <a href="<%= submission_path(submission) %>" class="btn btn-outline btn-sm w-full md:w-24" aria-label="<%= "#{t('view')} #{submitter.name || submitter.email || submitter.phone}" %>">
<%= t('view') %> <%= t('view') %>
</a> </a>
</div> </div>
<% if !submission.archived_at? && !template&.archived_at? && can?(:destroy, submission) %> <% if !submission.archived_at? && !template&.archived_at? && can?(:destroy, submission) %>
<span data-tip="<%= t('archive') %>" class="sm:tooltip tooltip-top"> <span data-tip="<%= t('archive') %>" class="sm:tooltip tooltip-top">
<%= button_to button_title(title: nil, disabled_with: nil, icon: svg_icon('archive', class: 'w-6 h-6'), icon_disabled: svg_icon('loader', class: 'w-6 h-6 animate-spin')), submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('archive'), method: :delete %> <%= button_to button_title(title: nil, disabled_with: nil, icon: svg_icon('archive', class: 'w-6 h-6'), icon_disabled: svg_icon('loader', class: 'w-6 h-6 animate-spin')), submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('archive'), aria: { label: "#{t('archive')} #{submitter.name || submitter.email || submitter.phone}" }, method: :delete %>
</span> </span>
<% end %> <% end %>
<% if local_assigns[:archived] && can?(:destroy, submission) %> <% if local_assigns[:archived] && can?(:destroy, submission) %>
@ -117,7 +117,7 @@
<div class="flex flex-col md:flex-row md:items-center gap-3"> <div class="flex flex-col md:flex-row md:items-center gap-3">
<% if is_submission_completed %> <% if is_submission_completed %>
<% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %> <% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %>
<a href="<%= submission_path(submission) %>" class="z-[1] tooltip flex" data-tip="<%= l(latest_submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>"> <a href="<%= submission_path(submission) %>" class="z-[1] tooltip flex" data-tip="<%= l(latest_submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>" aria-label="<%= t(latest_submitter.status) %>">
<span class="badge <%= status_badges[latest_submitter.status] %> md:w-32 bg-opacity-50 badge-lg uppercase text-sm font-semibold"> <span class="badge <%= status_badges[latest_submitter.status] %> md:w-32 bg-opacity-50 badge-lg uppercase text-sm font-semibold">
<%= t(latest_submitter.status) %> <%= t(latest_submitter.status) %>
</span> </span>
@ -134,19 +134,19 @@
<div class="relative flex justify-between items-start md:items-center space-x-3"> <div class="relative flex justify-between items-start md:items-center space-x-3">
<span class="flex flex-col md:flex-row md:items-center gap-2"> <span class="flex flex-col md:flex-row md:items-center gap-2">
<% if !is_submission_completed && !submission.expired? %> <% if !is_submission_completed && !submission.expired? %>
<a href="<%= submission_path(submission) %>" class="z-[1] tooltip flex" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>"> <a href="<%= submission_path(submission) %>" class="z-[1] tooltip flex" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>" aria-label="<%= "#{t(submitter.status)} #{submitter.name || submitter.email || submitter.phone}" %>">
<span class="badge md:w-24 <%= status_badges[submitter.status] %> bg-opacity-50 uppercase text-xs font-semibold"> <span class="badge md:w-24 <%= status_badges[submitter.status] %> bg-opacity-50 uppercase text-xs font-semibold">
<%= t(submitter.status) %> <%= t(submitter.status) %>
</span> </span>
</a> </a>
<% end %> <% end %>
<span class="flex items-center z-[1]"> <span class="flex items-center z-[1]">
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer"> <a href="<%= submission_path(submission) %>" class="text-lg break-all peer" aria-label="<%= "#{submitter.name || submitter.email || submitter.phone} #{t(submitter.status)}" %>">
<%= submitter.name || submitter.email || submitter.phone %> <%= submitter.name || submitter.email || submitter.phone %>
</a> </a>
<% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %> <% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>"> <span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %> <%= link_to edit_submitter_path(submitter), class: 'shrink-0', aria: { label: "#{t('edit')} #{submitter.name || submitter.email || submitter.phone}" }, data: { turbo_frame: 'modal' } do %>
<%= svg_icon('pencil', class: 'w-5 h-5') %> <%= svg_icon('pencil', class: 'w-5 h-5') %>
<% end %> <% end %>
</span> </span>
@ -167,7 +167,7 @@
<% elsif !template&.archived_at? && !submission.archived_at? && !is_submission_completed && !submission.expired? && !submitter.declined_at? %> <% elsif !template&.archived_at? && !submission.archived_at? && !is_submission_completed && !submission.expired? && !submitter.declined_at? %>
<div class="relative flex items-center space-x-3"> <div class="relative flex items-center space-x-3">
<% if current_user.email == submitter.email %> <% if current_user.email == submitter.email %>
<a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="absolute md:relative top-0 right-0 btn btn-xs btn-outline btn-neutral bg-white w-28 md:w-36 z-[1]"> <a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="absolute md:relative top-0 right-0 btn btn-xs btn-outline btn-neutral bg-white w-28 md:w-36 z-[1]" aria-label="<%= "#{t('sign_now')} #{submitter.name || submitter.email || submitter.phone}" %>">
<span class="flex items-center justify-center space-x-1 md:space-x-2"> <span class="flex items-center justify-center space-x-1 md:space-x-2">
<% if t('sign_now').length < 12 %> <% if t('sign_now').length < 12 %>
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %> <%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
@ -204,13 +204,13 @@
</div> </div>
<% end %> <% end %>
<div class="flex-1 md:flex-none z-[1]"> <div class="flex-1 md:flex-none z-[1]">
<a href="<%= submission_path(submission) %>" class="btn btn-outline btn-sm w-full md:w-24"> <a href="<%= submission_path(submission) %>" class="btn btn-outline btn-sm w-full md:w-24" aria-label="<%= t('view') %>">
<%= t('view') %> <%= t('view') %>
</a> </a>
</div> </div>
<% if !submission.archived_at? && !template&.archived_at? %> <% if !submission.archived_at? && !template&.archived_at? %>
<span data-tip="<%= t('archive') %>" class="sm:tooltip tooltip-top"> <span data-tip="<%= t('archive') %>" class="sm:tooltip tooltip-top">
<%= button_to button_title(title: nil, disabled_with: nil, icon: svg_icon('archive', class: 'w-6 h-6'), icon_disabled: svg_icon('loader', class: 'w-6 h-6 animate-spin')), submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('archive'), method: :delete %> <%= button_to button_title(title: nil, disabled_with: nil, icon: svg_icon('archive', class: 'w-6 h-6'), icon_disabled: svg_icon('loader', class: 'w-6 h-6 animate-spin')), submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('archive'), aria: { label: t('archive') }, method: :delete %>
</span> </span>
<% end %> <% end %>
<% if local_assigns[:archived] && can?(:destroy, submission) %> <% if local_assigns[:archived] && can?(:destroy, submission) %>
@ -220,6 +220,6 @@
<% end %> <% end %>
</div> </div>
<% end %> <% end %>
<a href="<%= submission_path(submission) %>" class="top-0 bottom-0 left-0 right-0 absolute"></a> <a href="<%= submission_path(submission) %>" class="top-0 bottom-0 left-0 right-0 absolute" aria-hidden="true" tabindex="-1"></a>
</div> </div>
</div> </div>

Loading…
Cancel
Save