Problem/Motivation

There are places in the core where we link out to external resources. One of these is in the installer when there is an unmet requirement. Another is in the date formatters, where there is a link out to the PHP docs so people can reference how to construct custom date strings. There are other places, and contrib space adds lots more.

There are some older, related issues about this for specific cases, but no consolidated policy that we can point to. External links are also handled inconsistently with regards to links opening in a new windows, rel=external, etc.

We should formalize our approach to how external links are handled, and as a follow-up, apply the policy, considering the proper context.

Policy should consider the current best practices for usability and accessibility, provide concrete usage examples, and allow for context-specific exceptions when needed.

Proposed resolution

The Drupal core Accessibility core gate states that a goal of core is to conform to WCAG 2.1. That standard has recommendations, https://www.w3.org/WAI/WCAG21/Techniques/general/G200, for this case.

Implementation/changes to core are being done in #2652272: Review (and in most cases remove) use of target="_blank" attribute outside the installer or update.php

Questions

Is it feasible to add a code sniff for target="_blank" in our CI testing?

Comments

mpdonadio created an issue. See original summary.

mpdonadio’s picture

Wanted to add some thoughts outside the IS.

This goes beyond deciding whether to target=blank all external links and making a big patch to make them one way or another. While this has the potential to be a bikeshed-o-rama and there is strong opinion against target=blank, it is also an opportunity to provide usability and accessibility improvements in core which can be implemented consistently, and also provide guidance for contrib.

For the sake of a starting point, I propose

- in general, external links should not open in new window
- in the cases where data loss may occur (eg, form entry), use target=blank
- use rel=external
- be compatible with #2207383: Create a tooltip component, which should also help with WCAG concerns

jhodgdon’s picture

Note @mgifford's comment #50 on the issue this was spawned from:

The accessibility pieces are essentially about user control. Opening up a new page to direct folks to a new page can be disorienting. It's a much better practice to teach users how to use their browser. It's really hard for some users to handle multiple screens (especially on a mobile device) even the browser has good support for them.

#2652272-50: Review (and in most cases remove) use of target="_blank" attribute outside the installer or update.php

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

lokapujya’s picture

Maybe external pages are ok for pages that are references for the opener page.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mgifford’s picture

Google's Lighthouse is now recommending https://developers.google.com/web/tools/lighthouse/audits/noopener

In general, always add rel="noopener" when you open an external link in a new window or tab.

Although that looks like it is just for target="_blank" links.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

flyke’s picture

Every link in Drupal 8 automatically gets rel="nofollow" thanks to this bit of code in core/modules/filter/src/Plugin/Filter/FilterHtml.php on line 140:

if ($this->settings['filter_html_nofollow']) {
      $links = $html_dom->getElementsByTagName('a');
      foreach ($links as $link) {
        $link->setAttribute('rel', 'nofollow');
      }
    }

I suggest adding a check here if that link has target="_blank" and if so, also adding the rel 'noopener':

if ($this->settings['filter_html_nofollow']) {
      $links = $html_dom->getElementsByTagName('a');
      foreach ($links as $link) {
        $link->setAttribute('rel', 'nofollow');
        if ($link->hasAttribute('target') && $link->getAttribute('target') == '_blank') {
          $link->setAttribute('rel', 'nofollow noopener');
        }
      }
    }

This will improve performance and prevent security vulnerabilities, as is described here:
https://web.dev/external-anchors-use-rel-noopener/?utm_source=lighthouse...

It will also remove this error from lighthouse site audits and thus improve your best practice scores:

Links to cross-origin destinations are unsafe

Could someone make this into a patch perhaps ?

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

andrewmacpherson’s picture

Use of target="_blank" is extremely disruptive for several groups of users.

It's strongly preferable to let the user decide whether they want to open the link in a new window/tab, or the current window. Using target="_blank" removes this choice from the user, and prevents the user from returning to the previous page by using the browser's "backwards" function. It isn't possible for users to override target="_blank" specified by a web page (if it was, that would be a game changer).

The relevant part of WCAG is success criterion 3.2.5 Change On Request. There are occasional circumstances where it's preferable to open a new window/tab. Some examples are discussed in WCAG advisory technique G200: Opening new windows and tabs from a link only when necessary.

However, I'd expect it to be RARE for a link to actually warrant target="_blank". If you think a link needs it... think again. It probably doesn't. (Rinse and repeat.)

Some bad reasons for using target="_blank":

  • The link points to a different web site.
  • The link points to documentation.
  • The link is on a form.
  • Reducing something called a "bounce rate".
  • Because the author/designer/developer wants it.

As for the policy, I'd say for any issue which proposes to introduce target="_blank":

  • The issue must provide a compelling reason why it is necessary.
  • Reviewers and committers should push back hard. No waving it through.
  • In rare instances where we do permit target="_blank", we really MUST warn users about what will happen. That means visible text to say the link opens in a new window (preferably inside the link itself).

Re. #2:

in the cases where data loss may occur (eg, form entry), use target=blank

This one is often the reason given (and waved through). It doesn't always hold water though; browsers are good at remembering form state when you use the back button. The mere fact that a link is on a form doesn't make it a good candidate for opening a new window. The steps for data loss should be demonstrated.

If I sound a bit militant here, it's because I am. It's easy to make links which fail WCAG Change on Request. It's even easier to make links which pass.

I like the approach in #13 of checking for target=_blank then adding rel=noopener. The contrib external links module does something similar to insert the "opens in new window" text.

There's an ATAG aspect to this; the system should guide authors to create accessible content. So if Drupal core provides tools for authors to create links with target="_blank", then it should also provide guidance for content editors to use it (effectively, persuade them not to). See ATAG B.2.2. Guide authors to produce accessible content and B.4.2. Ensure that documentation promotes the production of accessible content.

I have no opinion on rel=nofollow :-)

andrewmacpherson’s picture

Issue summary: View changes

An idea from @xjm in #3142818-19: Remove target=_blank from links in media settings forms

I think there should be a sniff to warn devs about <strong>target="_blank"</strong>, so tagging for a followup. Thanks!

I've added that to the proposed resolution here. Is it feasible? It could go in drupal/coder say. I think some accessibility testing tools have a sniff for this (HTML_codesniffer, aXe, or whichever). We don't have one of those in our CI system yet though.

andrewmacpherson’s picture

Issue summary: View changes

Oops, fixing bad HTML.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

The Drupal core Accessibility core gate states that a goal of core is to conform to WCAG 2.1. That standard has recommendations, https://www.w3.org/WAI/WCAG21/Techniques/general/G200, for this case.

There is an item here to add a sniff for target=_blank. But there are valid cases for using _blank so adding a sniff to to warn about it's use could be disruptive when running commit-code-check.sh.

Therefor, I think everything is done here.

Thanks everyone!

quietone’s picture

Version: 11.x-dev » 11.2.x-dev

Changing to latest version when this was closed.

baluertl’s picture

Issue summary: View changes
quietone’s picture

Status: Closed (outdated) » Needs review

@xjm reminded me that this should be check by the Accessibility maintainers. I will ping in slack.

xjm’s picture

Issue tags: +Needs followup

I think #24 is correct and we probably can't add a sniff disallowing target="_blank" to the core ruleset (unless we confirm that there really is not a single valid core usecase presently). It could potentially be a DrupalPractice sniff or something.

That said, I think core is definitely using target="_blank" in a number of places it should not. We should audit and remove most if not all of them.

xjm’s picture

Issue tags: -Needs followup
mgifford’s picture

Makes sense to me.

quietone’s picture

Issue summary: View changes
Status: Needs review » Closed (outdated)

@mgifford, thank you for responding here and in slack, confirming that this core gate is correct.

I updated the IS to say the implementation is to be done in #2652272: Review (and in most cases remove) use of target="_blank" attribute outside the installer or update.php.

Also restoring the outdated status.

xjm’s picture

Saving credits.