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

Command icon 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

manuel.adan created an issue. See original summary.

jlozande’s picture

Assigned: Unassigned » jlozande

jlozande’s picture

Issue summary: View changes
jlozande’s picture

Issue summary: View changes
jlozande’s picture

Issue summary: View changes
ivnish’s picture

Assigned: jlozande » Unassigned
Status: Active » Postponed (maintainer needs more info)

@manuel.adan could you explain what links do you mean?

jlozande’s picture

Issue summary: View changes
jlozande’s picture

Issue summary: View changes
ivnish’s picture

Version: 8.x-4.x-dev » 5.x-dev
Status: Postponed (maintainer needs more info) » Active
pgrandeg’s picture

If I am not wrong @ivnish, they mean about the flag/unflag links exposed in entity pages

deaom made their first commit to this issue’s fork.

deaom’s picture

Status: Active » Reviewed & tested by the community

The 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.

ivnish’s picture

Status: Reviewed & tested by the community » Postponed (maintainer needs more info)

Why do we it via JS ?

deaom’s picture

Status: Postponed (maintainer needs more info) » Needs review

I 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.

avpaderno’s picture

Issue tags: -accesibility +Accessibility
joachim’s picture

Would it be possible to do this before the twig layer? That way themes that override the template won't accidentally not include it.

deaom’s picture

Links 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.

deaom’s picture

Re-based branch, removed attribute from twig and added it to the build/render array.

ivnish’s picture

@joachim could you have a look?

joville’s picture

The 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

benstallings’s picture

Status: Needs review » Needs work

Claude 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.

joachim’s picture

LLM reviews are worthless slop. Please don't waste maintainers' time with them.

mgifford’s picture

They 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?

joachim’s picture

Reviews 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.

benstallings’s picture

Assigned: Unassigned » benstallings
benstallings’s picture

Assigned: benstallings » Unassigned
Status: Needs work » Closed (works as designed)

Apologies 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 probably aria-pressed: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Referenc... .

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

joachim’s picture

Status: Closed (works as designed) » Needs work

LLMs are not a 'source'. They're slop.

This issue shouldn't be closed AFAIK, just because the MR is apparently not the right approach.

benstallings’s picture

In 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

jelle_s’s picture

The 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.