primevue icon indicating copy to clipboard operation
primevue copied to clipboard

Improve Accessibility and HTML Compilation for Button Component

Open caiotarifa opened this issue 10 months ago • 4 comments

I'm writing to propose a critical improvement for the Button component in PrimeVue. Currently, there's a significant accessibility and HTML compilation issue when using buttons with links or router functionality. This has been reported multiple times in past issues (#1920, #3118, #3552).

Problem

Currently, to use a link or router functionality with a button, users have to resort to the following workaround:

<RouterLink to="/">
  <Button label="Go home" />
</RouterLink>

However, this approach can lead to accessibility issues and invalid HTML compilation, resulting in something like this:

<a href="/">
  <button>Go home</button>
</a>

Another problem that can occur is if the Button has the disabled property enabled, but a RouterLink encapsulates it, this can generate usability problems (see #5180).

As you can see in HTML5 Spec Document from W3C, it isn't valid.

Content model: Transparent, but there must be no interactive content descendant.

The a element may be wrapped around entire paragraphs, lists, tables, and so forth, even entire sections, so long as there is no interactive content within (e.g. buttons or other links).

Solution

I propose adding two new parameters to the Button component: to and href. Additionally, the root component should change from <button> to <component>. This way, it will be possible to dynamically control the component to be rendered.

For instance:

  • If to is used and RouterLink is available in the application, the "component is" attribute will be set to RouterLink.
  • If href is used, the <a> tag will be utilized (and all other valid parameters can be used, such as target).
  • If none of the parameters are used, then <button> will be rendered by default.

Example

Here's a simple example of how the proposed solution would work in a Vue 3 component using Composition API:

<template>
  <component :is="buttonComponent" :to="to" :href="href" :label="label" />
</template>

<script setup>
import { computed, defineProps, resolveComponent } from 'vue'
import { useRouter } from 'vue-router'

const props = defineProps({
  tag: {
    default: 'button',
    type: String
  },

  to: {
    default: '',
    // TypeScript: see about RouteLocationRaw interface.
    type: [String, Object]
  },

  href: {
    default: '',
    type: String
  },

  label: {
    default: '',
    type: String
  }
})

const router = useRouter()

const buttonComponent = computed(() => {
  if (props.to && router) {
    return resolveComponent('RouterLink')
  }

  return props.href ? 'a' : props.tag
})
</script>

Major Vue UI frameworks already provide solutions to this problem.

  • https://quasar.dev/vue-components/button
  • https://element-plus.org/en-US/component/button.html
  • https://vuetifyjs.com/en/api/v-btn/#links

This issue/solution is valid not only for Button, but also other components like Breadcrumb, Menu, MenuItem and others that require similar functionality.

caiotarifa avatar Apr 09 '24 13:04 caiotarifa

Totally agree, just stumbled upon this myself and was shocked that the documentation is suggesting using invalid HTML5 syntax as a way to achieve link button pattern. Pretty disappointed by this design decision

https://stackoverflow.com/a/6393863/7980639

slavco86 avatar Apr 10 '24 10:04 slavco86

@tugcekucukoglu I'd like to contribute by developing this improvement in v4 branch. Do you have plans to add this?

caiotarifa avatar Apr 13 '24 22:04 caiotarifa

Fully agreed, this issue and the devs' unwillingness to address it single-handedly put me off using PrimeVue. Components having valid HTML5 syntax seems like a bare minimum for an UI library.

zgronska avatar Apr 19 '24 14:04 zgronska

We also think this is crucial for improved developer experience and most of all, accessibility.

@caiotarifa Perhaps its worth a shot, implement this and open PR?

frasza avatar Apr 29 '24 07:04 frasza

Any updates for this? Seems like a no brainer...

BenJackGill avatar Aug 12 '24 02:08 BenJackGill

Hello,

We added as and asChild properties to Button in v4. Please try it; https://primevue.org/button/#link

mertsincan avatar Aug 12 '24 08:08 mertsincan