quasarframework / quasar

Quasar Framework - Build high-performance VueJS user interfaces in record time
https://quasar.dev
MIT License
25.75k stars 3.5k forks source link

QDate has buttons with inaccessible names #16713

Open hennzen opened 9 months ago

hennzen commented 9 months ago

What happened?

Our app needs to comply with WCAG guidelines, which is why we plan to integrate automated checks into our build pipeline as a first stop, prior to manual checks. We strive to reduce the amount of (sometimes non-critical or even purely technical as per specs) errors reported by Lighthouse et al., so that the important errors stay visible.

Currently, QDate's buttons to flip between months or years (chevron-left/-right) as well as the "today" button cause an error "Buttons do not have an accessible name" (Lighthouse) resp. "Buttons must have discernible text" (AxeDevTools).

I think it's important to note that this a11y issue might not be mission critical, if we only use the QDate in conjunction with QInput. Impaired users can always use the QInput then. That's our case, mostly, but we also display the QDate as a widget here and there, i.e. without QInput. So then it becomes important again.

What did you expect to happen?

The button elements should be using ARIA labels such as aria-label="[previous|next] [month|year]" or aria-label="today".

Reproduction URL

https://codepen.io/hennzen/pen/YzBmOVg

How to reproduce?

  1. Go to the provided CodePen
  2. Open DevTools to either use Lighthouse or AxeDevTools Tab
  3. Generate report

Flavour

Quasar CLI with Vite (@quasar/cli | @quasar/app-vite)

Areas

Components (quasar), Accessibility [a11y] (quasar)

Platforms/Browsers

Firefox, Chrome

Quasar info output

No response

Relevant log output

No response

Additional context

No response

pdanpdan commented 9 months ago

I know the problem (this one and the QTable navigation buttons one). The problem is that it needs lots of translations (all things should have i18n)

hennzen commented 3 months ago

To solve this, I ended up creating a patch patches/quasar+2.16.4.patch with patch-package, and while I was at it, also added a tooltip with custom class to the today button:

--- a/node_modules/quasar/src/components/date/QDate.js
+++ b/node_modules/quasar/src/components/date/QDate.js
@@ -1,6 +1,7 @@
 import { h, ref, computed, watch, Transition, nextTick, getCurrentInstance } from 'vue'

 import QBtn from '../btn/QBtn.js'
+import QTooltip from '../tooltip/QTooltip.js'

 import useDark, { useDarkProps } from '../../composables/private.use-dark/use-dark.js'
 import useRenderCache from '../../composables/use-render-cache/use-render-cache.js'
@@ -1131,13 +1132,21 @@ export default createComponent({

           props.todayBtn === true ? h(QBtn, {
             class: 'q-date__header-today self-start',
+            ariaLabel: 'today',
             icon: $q.iconSet.datetime.today,
             flat: true,
             size: 'sm',
             round: true,
             tabindex: tabindex.value,
             onClick: setToday
-          }) : null
+          }, () => h(QTooltip, {
+              class: 'ui-tooltip',
+              transitionShow: 'scale',
+              transitionHide: 'scale',
+              delay: 500,
+              hideDelay: 200,
+              anchor: 'top middle',
+              self: 'center middle' }, () => 'today')) : null
         ])
       ])
     }
@@ -1155,6 +1164,7 @@ export default createComponent({
             icon: dateArrow.value[ 0 ],
             tabindex: tabindex.value,
             disable: boundaries.prev === false,
+            ariaLabel: `${ type === 'Months' ? 'previous month' : 'previous year' }`,
             ...getCache('go-#' + type, { onClick () { goTo(-1) } })
           })
         ]),
@@ -1187,6 +1197,7 @@ export default createComponent({
             icon: dateArrow.value[ 1 ],
             tabindex: tabindex.value,
             disable: boundaries.next === false,
+            ariaLabel: `${ type === 'Months' ? 'next month' : 'next year' }`,
             ...getCache('go+#' + type, { onClick () { goTo(1) } })
           })
         ])

The patch applies to node_modules/quasar/src/components/date/QDate.js, and in order to make this work, the parent component needs an explicit import

import { QDate } from '../../../node_modules/quasar/src/components/date'

This took me some time to figure out, because a import { QDate } from 'quasar' is directed to the module's dist directory, which of course stays unaffected.

Can anyone think of a better approach, say JSProxy or something?

I would always try to avoid the extra maintenance of having patches in a project, but then again, this patch is clearly arranged enough (only added lines) to cause no headache.