govuk-frontend icon indicating copy to clipboard operation
govuk-frontend copied to clipboard

Add content to Skip link guidance about problem caused by preservation of fragment identifiers between pages

Open tombye opened this issue 1 year ago • 5 comments

The skip link component adds a #main-content fragment identifier to the current URL. This can persist across pages causing an unexpected jump to the main content area on load. I'd like to add a warning about this to the guidance, along with tips about ways teams could write their code to avoid this.

Related component

https://design-system.service.gov.uk/components/skip-link/

Context

This problem has been seen to happen in the following scenario:

  • the skip link was used, thereby adding #main-content to the current URL
  • you leave the page via a successful form submission
  • the form doesn't set the action attribute and so POSTs to the current URL
  • the server uses the POST -> Redirect -> GET pattern to navigate to the next page

Given all that, the browser will preserve #main-content in the new URL[^1] causing the next page to jump to the start of the main content area when it loads.

This was picked up as an issue by the Digital Accessibility Centre (DAC) in a recent audit of GOV.UK Notify[^2], who stated that it failed the WCAG 2.4.3 (Focus Order) success criteria.

Given the POST -> Redirect -> GET pattern is so commonly used in web apps, I think there's some value in making teams aware of this problem and helping them write their code in a way that stops it happening.

Alternatives

N/A

Additional information (if applicable)

Suggested changes, to stop the problem occurring are:

  • setting the action attribute on the <form> tag to match the current URL, without #main-content
  • setting the URL for the next page explicitly using the Content-Location header

References

[^1]: This is correct behaviour, as defined in Handling of fragment identifiers in redirected URLs [^2]: Issue 'ID: DAC_Focus_order_01' on page 19 of the audit report (needs a GDS Google account for access)

tombye avatar Nov 14 '23 17:11 tombye

Will investigate if this can be fixed in code before deciding on any content. Also if this affects other components.

calvin-lau-sig7 avatar Nov 17 '23 10:11 calvin-lau-sig7

We also has this issue picked up in an accessibility audit.

It flagged that the URL fragment ‘#main-content’ was persisting between page redirects, which “could be confusing and disorienting for screen reader and keyboard only users, who would expect focus to begin at the top of the page.”

Part of the issue is an inconsistency of approach; as outlined above, all our forward submit buttons on each form page preserve the skip link fragment, due to the native browser behaviour for 3xx redirects, but any link with a href does not (eg. back buttons, links in the footer). Where the fragment is preserved, focus begins at the heading level 1 or first form field of the newly loaded page. Where it isn’t preserved, it will be at the top of the next page, at the skip link. The auditors felt that this was focus “behaving unexpectedly”, in a manner that could be “confusing and disorienting” .

The auditors have suggested that focus always begins at the top of newly loaded pages, at the beginning of the

element (ie. at the skip link), as “this will make the navigation more predictable and understandable to screen reader and keyboard only users.”

We’re not sure this advice is correct. We think that:

  1. Keyboard users don’t want to always have to skip header / menu content on every page
  2. While more consistent, the burden of making the skip link required on every page would be a worse outcome for users than having it persist 90% of the time
  3. This is browser built in behaviour for 3xx redirects, defined in the HTML specification, and we shouldn't override that sort of thing without strong reason

If you do have any suggestions on what course of action will lead to the best experience for users, we'd be happy to hear them!

jordan-carlton avatar Feb 13 '24 10:02 jordan-carlton

We have also reached out on "cross gov" slack about this, but had not much response yet.

Worth noting that this behaviour (i.e. preserve skip to main content across multiple form pages) has been live on our high traffic service "Register to Vote" for at least 5 years without any complaints from screen reader / keyboard users or accessibility testers until our recent accessibility audit on a new service using the same UI framework.

Technically, it would be easy enough to suppress this behaviour by adding an "action" attr to all our forms. All other gov sites I have checked already do that. I think it would be worse for our users as per Jordan's comment above.

cc https://github.com/alphagov/govuk-design-system-backlog/issues/66

We would welcome any input on this from GDS

RichardBradley avatar Apr 03 '24 10:04 RichardBradley

Since I raised this issue, my team (GOV.UK Notify) has implemented a fix for the issue so its worth adding an update.

We decided that fragment identifiers should be stripped from URLs used in POST requests and chose the approach of setting the action attribute to the URL of the page.

We felt that the reasons fragment identifiers are carried through seemed related to the use of HTTP requests for 'resources', so more about how APIs use HTTP than user interfaces in web browsers. The GET -> REDIRECT -> POST pattern for web pages carrying through the fragment seemed more like an accident of how empty actions are interpreted and adherence to the HTTP spec. The latter has to work for both APIs and user interfaces in web browsers so cannot prioritise the needs of our (website) users.

When we looked at pages we redirect to, they are often very different from the one you came from. Even when they aren't, like pages that make up parts of a transactional journey, we have evidence from an accessibility audit that that situation can also be confusing for most users, particularly those using screen readers, or not.

In terms of the approach, we had to change a lot of pages so were mainly guided by the risks involved. The risk of changing the action was easier for us to manage than adding Content-Location for all POST requests and our code had access to the page URL so the implementation was fairly simple. I could imagine that decision being different if you worked on a project where the HTML was harder to change or the test coverage for the HTML in pages wasn't as comprehensive.

We looked into just setting action="#" to flush the fragment identifier. This did work but we felt the intent was less clear when reading the code and we worried about the impact of this being added to the browser history.

tombye avatar Jun 18 '24 11:06 tombye

Fair enough. I think those are all good points, thanks for sharing.

I do agree that the default behaviour here from the HTTP spec is not clear as to whether it's for the reasons we want or for unrelated historical issues.

When we looked at pages we redirect to, they are often very different from the one you came from.

Our services, which are public facing "application" questionnaires, have lots of very similar questions one after the other. Our main service has 15+ questions, each of which are very similar in UI / page layout.

We have had inconsistent responses in our accessibility testing. Some users like not having to re-skip the headers on each question, some find it confusing, and most seem to not notice until they're asked.

Personally, I had to do an personal application for something recently on a Gov Design System website, and I'm sighted but like to use the keyboard, and I found it terribly irritating to have to re-skip the header on every single page. I do hope GDS decide to promote this behaviour for multi-question forms, rather than ban it.

Maybe the ruling should be that it's kept in place for multi-question forms, but suggested against for other purposes. Further user research is certainly needed.

RichardBradley avatar Jun 18 '24 11:06 RichardBradley