- 8-A: Keyboard alternative for drag-and-drop field placement
- Default field items: tabindex/role=button + Enter/Space to emit add-default-field
- Field type grid buttons: keyboard click (event.detail===0) adds field directly (skips draw mode)
- builder.vue: addDefaultField() handles keyboard-triggered field insertion + announces via aria-live
- 8-B: Context menu keyboard trigger on placed field areas
- area.vue: tabindex=0 + areaLabel computed + onAreaKeydown handler
- ContextMenu key / Shift+F10 synthesizes MouseEvent('contextmenu') at element center
- 8-C: Field settings dropdown focus trap
- label @focus renders dropdown for keyboard users
- @keydown.escape.stop closes dropdown
- 8-D: Live region announcements for field add/remove
- announcePolite() called in addField(), addDefaultField() (builder.vue), and removeField() (fields.vue)
- i18n: field_type_added + field_removed keys added in all 7 languages (en/es/it/pt/fr/de/nl)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All DaisyUI dropdown content elements had tabindex="0" which put the
entire menu container in the keyboard tab order, causing our :focus-visible
rule to outline the whole dropdown box rather than individual menu items.
Changed to tabindex="-1" in 14 files (3 ERB + 11 Vue):
- submissions_filters/_filter_button.html.erb
- shared/_templates_order_select.html.erb
- submissions/show.html.erb
- template_builder/{payment_settings,field_type,field,builder,
custom_field,upload,google_drive_document_settings,area,
font_modal(x2),field_submitter(x2),mobile_fields}.vue
tabindex="-1" keeps mouse-click focus working (DaisyUI :focus-within
CSS still fires) while removing the container from the Tab order.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>