Skip to main content

Screen-reader Accessibility Assessment

Scope and overall assessment​

There are useful accessibility foundations, but the core UI should not currently be described as reliably blind-user-friendly. Several important controls expose text or buttons, but omit the relationships and states a screen reader needs to understand invoice selection, coding, and feedback.

This assessment is based on a static source review of production Vue components under ExFlowWeb/Client. It is not an inspection of a running browser's accessibility tree, a screen-reader test, or a complete WCAG audit. It identifies concrete omissions but does not establish a WCAG conformance level. Line references describe the source reviewed and may change over time.

Highest-impact findings​

PriorityFindingEffect on blind usersSource
CriticalCheckbox/radio controls are implemented as buttons with changing icons, without checkbox/radio roles or checked state.A screen reader can announce a button, but not whether the option is checked. This affects selection, settings, and mass approval.XBoolean.vue:2
CriticalCoding dropdowns lack combobox/listbox semantics: no expanded state, associated options list, active option, or selected-option state. Highlighting is CSS-only.Arrow keys may change the highlighted item without telling the screen reader which account, dimension, or approver will be selected.XInputMenu.vue:2–7, XBtnMenu.vue:25–37
HighInbox and invoice-line grids use generic div elements without table/grid header relationships or row-selection semantics.Values may be readable as separate text, but users lack reliable column, row, and selection context. Repeated fields are difficult to distinguish.XList.vue:3–43, XDocLines.vue:76–104
HighSome controls have no meaningful accessible name.Users encounter an unexplained "button" instead of its purpose. Examples include mass-approval selection controls and Boolean invoice fields.XListSearch.vue:24,63, XDocLineField.vue:20–24
HighPopup containers lack dialog semantics, an associated title, and explicit background exclusion/focus containment for true modal dialogs.Users may not know a dialog opened or where its boundaries are; background content may remain available. Escape/focus-return handling exists in some paths, but is not a complete dialog pattern.XBtnModal.vue:7–11, XModal.vue:2–6
HighValidation messages are not programmatically associated with inputs; custom errors do not set aria-invalid.Users can reach an input without hearing why it is invalid or what must be corrected.XInput.vue:8–11
HighToasts and invoice-action messages lack live-region semantics. Toasts normally disappear after seven seconds.Save results, warnings, and failures may appear without being announced, then disappear before the user finds them.XToast.vue:4–17,70, XDocActions.vue:21–35

Additional concrete naming defects​

In XDocLines.vue:10 and 16, two icon-only buttons use :tile instead of :title. Consequently, their intended "remove" and "apply" names are not supplied to the button component.

Document reading​

The PDF viewer is not entirely inaccessible canvas content: it renders a PDF.js text layer. That is a useful foundation.

However:

  • Off-screen pages are removed, including their text layer.
  • Later pages initially exist as placeholders.
  • The inspected wrapper does not build a structured PDF accessibility layer connecting headings, tables, and reading order.
  • Empty/error feedback is an icon rather than an explanatory text message.

See XPdfViewer.vue:203–230, XPdfViewer.vue:281–305, and XPdfViewer.vue:322–350.

Whether a blind user can review a complete multi-page invoice is a high-priority runtime test. Scanned invoices also need an accessible text alternative; a PDF text layer alone cannot provide text that is absent from the document.

The inbox has a similar risk: its off-screen item content can be replaced with an empty element in XListSearch.vue:19–21.

The inspected Vue shell largely uses generic containers rather than named main, navigation, and content regions. Navigation buttons do not announce the current section, and XTabs.vue:2–11 does not expose tab/selected-panel relationships.

These are not necessarily absolute blockers, but make screen-reader navigation substantially harder.

Existing foundations​

  • XBtn uses native buttons and derives accessible names from text/title.
  • XInput and text areas generally supply accessible labels.
  • Primary invoice actions have meaningful names, and the invoice caption is an actual heading.
  • Keyboard shortcuts and some focus-return handling are implemented.
  • Decorative SVG icons use presentation semantics.
  • The PDF viewer provides a text layer.

Keyboard support is valuable, but does not substitute for accessibility-tree semantics.

Start with shared components:

  1. Expose correct roles, names, and checked states for toggles.
  2. Implement accessible dropdown semantics and active-option announcements.
  3. Give true modal dialogs names, dialog semantics, and appropriate focus/background handling. Distinguish dialogs from menus and other nonmodal popovers.
  4. Associate descriptions/errors with inputs and expose invalid state.
  5. Announce status changes and errors without requiring users to find transient messages.

Improvements there would benefit many pages immediately. Then address grid relationships, navigation structure, and complete document reading.

Runtime validation checklist​

Validate with NVDA and Microsoft Edge, using the browser accessibility tree to inspect roles, names, states, and relationships:

  • Select an invoice and hear its identity and selection state.
  • Navigate coding suggestions and hear every highlighted option.
  • Open/close a dialog and verify focus and background isolation.
  • Trigger validation and hear the field-specific error.
  • Save, approve, or provoke a failure and hear the result.
  • Read a multi-page invoice and a long inbox without relying on visual scrolling.

The source evidence is enough to justify remediation now, but a blind-user-friendly claim should wait until those workflows work end-to-end with a screen reader.


Request for your developers​

Accessible names (aria-label on icon-only buttons)​

  • Profile menu, search history, search criteria and the ⋮ menus
  • Line options (#lines-options) and the “more” and “options” buttons
  • The counters for chat messages and attachments, ideally as a labelled button, such as “2 messages” and “1 attachment”

Semantics​

  • If feasible, give the inbox list and the line grid role="table", row and cell, or grid.

Test IDs (data-testid)​

  • Inbox: row (with the invoice id), filter and refresh
  • Invoice: Approve, approver summary and amount fields
  • Lines: line row, split action, and the split dialog fields and confirm
  • Chat: input, send, message list and a single message
  • Attachments: list, upload input and download