eslint-plugin-jsx-a11y: Link without href with role "button" should not be treated as non-interative content

  <a role="button" onClick={someWeirdlyNamedClickHandler}>
    Flow content model
  </a>

<a> in this case is interactive and is acting as button, since <button> allows only phrasing content inside itself and <a> has a transparent content model, it is not possible to use button is place of link with click handler to make a conforming html

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 23 (12 by maintainers)

Most upvoted comments

@dantix an a tag without a valid href is not focusable as it is not seen as a valid link.

Therefore <a role="button" tabindex="0" onClick={someWeirdlyNamedClickHandler}> could also have been a div. The a tag has no meaning anymore.

Not only that, but a button element should also be activated by enter and spacebar, therefore it would also need a keyboard handler to fully act as a button.

The idea here contravenes the first rule of ARIA https://www.w3.org/TR/aria-in-html/#rule1

Whereas it is totally possible to create a button like this, an accessibility checker should reflect the first rule of ARIA instead. In other words, just use a button 😃

@dantix yep I know. Strictly speaking, href="#" is just an incomplete fragment identifier šŸ˜‰ it’s not a valid value even if validators will pass it. Using tabindex="0" would be slightly better but at that point I’m not sure why one would want to make something like this: <a role="button" tabindex="0" onClick={someWeirdlyNamedClickHandler}>

and not use a button instead.

@AlmeroSteyn

The tabindex is added to make it focusable again, after it was a focusable element in the first place but ā€˜broken’ by not adding a valid ā€˜href’. So three ā€˜hints’ required just to get the same functionality a ā€˜button’ would give. So my question is, would a hint to the developer to use a ā€˜button’ instead not be a viable alernative? One vs three 😃

Over the years I’ve shifted from dogma to pragma on this issue. I’m foremost concerned with the user experience and less so with the code the produces it. As long as the experience is satisfactory, I’m willing to forgo strong opinions on how the code is structured. Especially so if this relaxed attitude brings along more developers. Some developers might find it easy to add a few extra attributes and proxy a key press event to a click handler than go mucking about with CSS to restyle a native button element. By allowing both paths, we naturally make more UIs accessible. I’m mostly thinking of the case where a common component is used throughout a product. Changing a span to a button or adding an href to an tag can have visually presentation effects that are non-deterministic, especially given a tangle of CSS across products. Using ARIA has zero display effects and its safer to make this changes on a large scale (we make hundreds of changes at a time).

Then say later, or during the maintenance phase of the code, someone else sees there is a handy anchor tag and adds a valid href. What then?

Valid point, although we can’t know why an href is added. Maybe it’s there for progressive enhancement. Clicking the button loads a modal dialog in the case where JavaScript exists, but navigates to a form in the absence of it. I think our task is to provide just enough advice to point to a good decision, but pull back just at the point of being acerbically prescriptive.

My thoughts on these issues are always evolving. I appreciate the debate. I’m using a bunch of these rules at large scale now, so time will tell what unforeseen behavior they engender. One thing I’ve already noticed is a growing incidence of tabbable elements inside tabbable elements. This is something we’ll need to address at a high level of composition.

Just to support @AlmeroSteyn here, Mozilla docs have an explicit warning about this:

Warning: Be careful when marking up links with the button role. Buttons are expected to be triggered using the Space or Enter key, while links are expected to be triggered using the Enter key. In other words, when links are used to behave like buttons, adding role=ā€œbuttonā€ alone is not sufficient. It will also be necessary to add a key event handler that listens for the Space key in order to be consistent with native buttons.

@n1313 ā€˜perfection’ can be judged from various angles. If looking at the elements from a semantic perspective and how they are defined and supposed to function and be used, using buttons as buttons and anchors as anchors would be considered the perfect solution. Deviating from the intention of the elements will invariably lead to functional issues.

I cannot offer a solution to your problem as I would really not do it this way. Seriously long control element texts are confusing to sighted and non sighted users alike. Therefore I prefer, when I do something like this, to keep it short and simple describing only the action being performed, or not no intermingle actions with paragraphs of text.

I would always recommend rather adjusting the layout to better make use of the intention of the HTML than to paint myself into a corner which forces me to abandon HTML semantics. Not doing this could lead to a website that I find visually pretty myself, but in doing so I’d be making it hard to impossible for actual people out there to use it.

@jessebeach thanks for sharing your thoughts on the matter.

Firstly let me say I am already happy that you are building and maintaining this tool. It is really great.

I do agree that a more accessible outcome is really the true win and that a11y eutopia rarely exists. So if this leads to more people being able to use websites despite what could be viewed as ā€œbadā€ HTML, goal achieved.

That said I do want to want to add the following to the <a type="button" discussion. When it comes to non semantic elements, such as div I would always propose using a native element instead of going for ARIA in the first place, but hey, if someone makes an accessible website with ARIA, then okay.

But the anchor is such a base functional element of the web. And users and developers alike generally know and expects what it does, that is, to navigate.

The solution above will no doubt make something that acts like a button, also to AT, given that the developer added tabindex="0" to it, added role="button" and also knew to add a keyboard handler that reacts to both enter and spacebar.

The tabindex is added to make it focusable again, after it was a focusable element in the first place but ā€˜broken’ by not adding a valid ā€˜href’. So three ā€˜hints’ required just to get the same functionality a ā€˜button’ would give. So my question is, would a hint to the developer to use a ā€˜button’ instead not be a viable alernative? One vs three 😃

Then say later, or during the maintenance phase of the code, someone else sees there is a handy anchor tag and adds a valid href. What then? Should the linter then warn them to remove the href because it is really actually a button even though it is an anchor tag in the HTML? Because such a hybrid could very easily end up being unusable by a screen reader user. You’d have a button that completely changes context on click without warning.

I would think that as the rules can be turned off and on, this would already give enough flexibility for it not to be blocking and a developer that is hinted to use a button can ignore it just like another one being hinted to now add more ARIA and handlers to the anchor can.

But as I said these are just my thoughts and it is up to you guys to best guard the vision of what you want this awesome tool to be. It certainly is not one or the other, as both would lead to accessible solutions, but the anchor / button decision does lead to a lot of a11y problems out there.

ā€œJust using a buttonā€ is not a perfect alternative to using a link (or a styled span), because you can’t apply display: inline to a <button>, it will remain rendered as inline-block (see http://stackoverflow.com/a/27658723, https://www.w3.org/TR/html5/rendering.html#the-button-element-0). In some cases this will not be good enough.

Here’s a live demo of the problem: https://jsbin.com/jewaporihe/edit?html,output. What would be your suggestion in this case @AlmeroSteyn?