govuk-frontend
govuk-frontend copied to clipboard
Components failing initialisation break due to `.js-enabled` styles
It is possible for components to be in a completely broken state if the user has JavaScript enabled but the GOV.UK Frontend bundle fails to download.
Previously we detected the presence of GOV.UK globally on window, but we removed this since we could not be sure if people would be using bundlers which will not output a global.
https://github.com/alphagov/govuk_template/blob/master/source/views/layouts/govuk_template.html.erb#L113
We could consider, injecting a global whenever a component is loaded that can remove js-enabled.
Potentially something like:
if (not already injected) {
window.___GOVUKFrontendComponentInitialised___
}
// tabs.js
import 'inject-global-initialised'
// only injects if not already injected before
inject()
// rest of tabs code here
// template.njk
<script>if(!window.___GOVUKFrontendComponentInitialised___) { // remove js-enabled }</script>
</body>
https://trello.com/c/oRDkiAz9/1448-frontend-components-appeared-styled-when-js-blocked
Potentially by solving https://github.com/alphagov/govuk-frontend/issues/1127 we could then use that to solve this issue.
Since they both rely on knowing of instances of GOV.UK Frontend components on the page.
We could then say if no instances were set, then assume something blew up.
We had a similar issue in my service this week. For reasons our service's js file for IE failed to compile so our service's js wasn't available in IE - but we still had the js-enabled class. This caused the worst of both worlds - fields with conditional content were hidden and there was no way to get to them.
If there are recommended solutions - like testing for a variable I'd be keen to hear them.
Hello all,
Currently experiencing this issue- what was the fix for this?
Thanks
![]()
It is possible for components to be in a completely broken state if the user has JavaScript enabled but the GOV.UK Frontend bundle fails to download.
Previously we detected the presence of
GOV.UKglobally on window, but we removed this since we could not be sure if people would be using bundlers which will not output a global.https://github.com/alphagov/govuk_template/blob/master/source/views/layouts/govuk_template.html.erb#L113
We could consider, injecting a global whenever a component is loaded that can remove js-enabled.
Potentially something like:
if (not already injected) { window.___GOVUKFrontendComponentInitialised___ }// tabs.js import 'inject-global-initialised' // only injects if not already injected before inject() // rest of tabs code here// template.njk <script>if(!window.___GOVUKFrontendComponentInitialised___) { // remove js-enabled }</script> </body>https://trello.com/c/oRDkiAz9/1448-frontend-components-appeared-styled-when-js-blocked
E
When www.gov.uk was down today and I wanted to send someone a link to it via the Wayback Machine, I found that I couldn't get to any of the main links within an accordion because the JavaScript wasn't archived. Although the page in question was not using the accordion from the Design System, I checked that the effect on the Design System accordion would be the same.
So, here is that real world example: http://web.archive.org/web/20210205010100/https://www.gov.uk/service-manual/helping-people-to-use-your-service
Usually, when you click on "Meeting accessibility requirements", the section underneath would open and reveal a couple of links. This is worse than Nick's original example because it's impossible to get to the links and you cannot even see that anything is missing.
useEffect(() => { document.documentElement.classList.add(‘govuk-template’); document.body.classList.add(‘js-enabled’, ‘govuk-template__body’); }, []);
Place this code into your root component, this fix works for me!!
Hello all,
Currently experiencing this issue- what was the fix for this?
Thanks
It is possible for components to be in a completely broken state if the user has JavaScript enabled but the GOV.UK Frontend bundle fails to download. Previously we detected the presence of `GOV.UK` globally on window, but we removed this since we could not be sure if people would be using bundlers which will not output a global. https://github.com/alphagov/govuk_template/blob/master/source/views/layouts/govuk_template.html.erb#L113 We could consider, injecting a global whenever a component is loaded that can remove js-enabled. Potentially something like: ```js if (not already injected) { window.___GOVUKFrontendComponentInitialised___ } ```
// tabs.js import 'inject-global-initialised' // only injects if not already injected before inject() // rest of tabs code here// template.njk <script>if(!window.___GOVUKFrontendComponentInitialised___) { // remove js-enabled }</script> </body>https://trello.com/c/oRDkiAz9/1448-frontend-components-appeared-styled-when-js-blocked
E
Adding a list of scenarios from:
- https://github.com/alphagov/govuk-frontend/pull/3095#issuecomment-1348771603
For context: We improved Accordion sections to be visible during page load in https://github.com/alphagov/govuk-frontend/pull/3053 but for slow-loading pages we saw a visual layout shift as each section flickered closed (from open) after initialisation
We'd like to review similar components load with:
- JavaScript off
- JavaScript on but crashed
- JavaScript on but skipped checks
- JavaScript on but took too long
(Where "skipped checks" could be an early return false after a query selector check fails)
An example of this came up last Friday in an incident on GOV.UK. A change was rolled out which introduced an error in their analytics JavaScript, which caused the JS for other components to fail. From their incident doc (internal, only visible to folks from GDS):
A change to JavaScript code in govuk_publishing_components that loads Google Analytics made it though to production in a bad release of Static, resulting in user interface code failing to load. This broke all JavaScript features (search button, menu bar etc.) on pages which have scroll-tracking analytics. This made all content behind "accordion" drop-down widgets — such as those on the www.gov.uk/coronavirus landing page — unviewable to Chrome and Firefox users.
Off the back of this, GOV.UK have wrapped the initialisation of each component in a try / catch block to try and limit the impact of errors in any individual JavaScript module.
Although we now have a recent example of why this is a problem, it's still come up (surprisingly) rarely since this issue was raised, so at the minute this isn't going to be prioritised over the work planned for the next quarter, but we hope to look at this soon.
Before they get lost, a scrappy attempt to capture potential ideas to explore from various people on Slack, in no particular order:
- remove the
js-enabledclass from the body if an error occurs - consider using a different kind of progressive enhancement for the accordion – e.g. a link and a :target selector so we have a layout closer to the final one until JS kicks in
- use
<details>elements (probably not – see https://github.com/alphagov/govuk-frontend/pull/958#issuecomment-421365887, https://daverupert.com/2019/12/why-details-is-not-an-accordion/, https://adrianroselli.com/2019/04/details-summary-are-not-insert-control-here.html and https://www.scottohara.me/blog/2022/09/12/details-summary.html) - have a “smoke and mirrors” class that we temporarily add with a setTimeout? This is the maximum time the Accordion should stay closed to avoid layout shift. Bit like how we try to load an
@font-faceby staying blank before falling back, but ideally the Accordion would finish loading before the “smoke and mirrors” class gets removed—if not they fail safe to open state - our all.js script that initialises all of our modules would be subject to the same kind of issue that happened to GOV.UK. If an early module throws, later modules won’t get initialised. We’re quite defensive in the code initialising each module already to avoid throwing, but we may want to give it a proper look (and maybe implement something akin to the suggestion to wrap initialising loop in try/catch to let further modules work OK).
- it’s also likely that many services have the same need of initialising multiple JavaScript modules in a row, without the failure of one breaking those that come after. It could be something we provide some solution for as part of govuk-frontend (not necessarily a trivial thing if we need to consider modules trying to call each other and maybe having to load asynchronously, so we may only be able to provide only part of a solution).
On GOV.UK we've just implemented wrapping each module initialisation in a try/catch block. It should stop one module from taking down the whole page, but won't solve the accordion problem if it's the accordion that fails to initialise properly.