Problem/Motivation
Links without type="button": Links that act as buttons do not include the type="button" attribute, which can cause accessibility and usability issues.
Accessibility Criteria Not Met:
This issue do not meet several criteria of the Web Content Accessibility Guidelines (WCAG) 2.1, including:
Criteria 1.3.1 (Information and Relationships): Links that act as buttons must be identifiable and operable as such.
For more information on this criteria, please refer to the WCAG 2.0 Success Criteria.
Steps to reproduce
N/A
Proposed resolution
Add button type to the link.
Remaining tasks
Patch and review.
User interface changes
Visually none.
API changes
N/A
Data model changes
N/A
Issue fork flag-3512977
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
jlozande commentedComment #4
jlozande commentedComment #5
jlozande commentedComment #6
jlozande commentedComment #7
ivnish@manuel.adan could you explain what links do you mean?
Comment #8
jlozande commentedComment #9
jlozande commentedComment #10
ivnishComment #11
pgrandeg commentedIf I am not wrong @ivnish, they mean about the flag/unflag links exposed in entity pages
Comment #13
deaom commentedThe type=button is added to links and no functional change or style change is happening, so can be merged. Do not have enough permissions to change the target branch in the MR, so that needs to be updated before merging, but did rebase to latest 8x. Setting status to RTBC.
Comment #14
ivnishWhy do we it via JS ?
Comment #15
deaom commentedI assume it was the easiest way to target the links as the for loop is already there. Did remove it from JS and added it directly in flag twig. Needs review.
Comment #16
avpadernoComment #17
joachim commentedWould it be possible to do this before the twig layer? That way themes that override the template won't accidentally not include it.
Comment #18
deaom commentedLinks are build out in the ActionLinkTypeBase.php with their build array, so possibility to add it there. Will be present in the attributes, so if whoever overrides the template does not include that, it will not be added.
The other possibility is the way it was before, with JS.
Comment #19
deaom commentedRe-based branch, removed attribute from twig and added it to the build/render array.
Comment #20
ivnish@joachim could you have a look?
Comment #21
joville commentedThe attribute type="button" on a link element is not valid html5, makes only sense on a button or input element in this way.
The HTML5 Validator (https://validator.w3.org) shows: "Bad value button for attribute type on element a". On a link there is only the mime-type attributable with type.
Therefore this has no improvements or implications for accessibility.
https://html.spec.whatwg.org/#links-created-by-a-and-area-elements
https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html
Comment #22
benstallings commentedClaude Code says:
● Review — branch 3512977-set-link-flag (issue #3512977)
Goal per issue title: set the flag link to behave as a button for accessibility. Net diff is one line in src/ActionLink/ActionLinkTypeBase.php:120 adding '#attributes' => ['type' => 'button'] to the render array returned by getAsFlagLink().
This fix is broken — it does not achieve accessibility.
The flag link renders as an
<a>anchor (see templates/flag.html.twig:41:<a{{ attributes }}>{{ title }}</a>). With this change the output becomes:<a type="button" rel="nofollow" href="..." title="...">Bookmark</a>type="button" is not valid on an
<a>element. In HTML, type on<a>is a MIME-type hint (e.g., type="text/html") and has no button semantics. type="button" is only meaningful on<button>and<input>. Browsers silently ignore unknown type values on anchors, so nothing breaks — but:1. The rendered HTML is invalid (W3C validators will flag it).
2. Assistive technology still announces the element as "link," not "button." Screen readers key on the element's role, not an unrelated type attribute.
3. No keyboard behavior changes — anchors already activate on Enter; buttons also activate on Space, but that would require JS or an actual
<button>.The idiomatic accessibility fix is role="button", not type="button":
'#attributes' => ['role' => 'button'],With role="button":
- Screen readers announce "button" instead of "link."
- ARIA semantics convey that activation performs an action rather than navigation.
- Also standard guidance: if you use role="button" on an
<a>, you should add Space-key handling in JS (the module's existing JS libraries already handle flag link activation, so this would just need verification). Alternative: render a real via the twig template — more invasive.This should not merge as-is. The change does the motion of the fix but uses the wrong attribute name.
Secondary issues
- No test. A fix for a specific rendered attribute needs a test asserting the attribute appears on the flag link (functional or kernel-level rendering assertion). Without one, even after correcting the attribute, there's nothing to prevent regression.
- #attributes is set on all render-array code paths but only consumed when an
<a>actually renders. The anonymous-unauthorized branch (line 149) keeps #attributes but the twig renders instead of<a>when title is empty. The attribute silently disappears in that branch. That's acceptable behavior but worth being aware of — once you switch to role="button", it's still only meaningful on the link branch.What I'd ask for before merge
1. Change 'type' => 'button' to 'role' => 'button'.
2. Verify keyboard activation (Space key) with the module's existing JS, or document that only Enter is supported.
3. Add a kernel test rendering
getAsFlagLink()and asserting the role attribute is present on the link.Comment #23
joachim commentedLLM reviews are worthless slop. Please don't waste maintainers' time with them.
Comment #24
mgiffordThey can be @joachim but not sure that they always are. This one is longer than the original post, so ya, probably not very useful.
But do we define want a good review to look like. We have this:
https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquett...
and
https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquett...
But have we defined what we want them to look like? How we make them not maintainers users time?
People are going to continue posting them, as they want to fix things but don't know how. Can we direct that in a way that will be more useful?
Comment #25
joachim commentedReviews require thought. LLMs can't think or analyse, they're just token predictors.
I refuse to read a review into which no thought has gone.
Comment #26
benstallings commentedComment #27
benstallings commentedApologies for citing a source and giving the impression that I hadn't also thought about it. I'll take greater care in the future!
In summary, this MR doesn't do anything to change behavior of screen readers because
<a type="button">is not valid HTML. If the links don't work as desired, the solution is probablyaria-pressed: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Referenc... .Comment #29
joachim commentedLLMs are not a 'source'. They're slop.
This issue shouldn't be closed AFAIK, just because the MR is apparently not the right approach.
Comment #30
benstallings commentedIn that case we should probably link to a version of the WCAG guidelines that is not 8 years out of date like the one in the issue description. Here's the current one: https://www.w3.org/WAI/WCAG22/quickref/#name-role-value
Comment #31
jelle_sThe flag module already had several options how to render a flag link (regular link, ajax link, confirm form, ...)
We could add another option to render it as an actual
<button>? It would also make it harder for crawlers to crawl the flag/unflag links if flags are enabled for anonymous users.