-
Notifications
You must be signed in to change notification settings - Fork 268
Implement accordion for mobile navigation #4701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement accordion for mobile navigation #4701
Conversation
✅ You can preview this change here:
To edit notification comments on pull requests, go to your Netlify project configuration. |
79dbca4 to
35b5b02
Compare
|
Opened a Merge request on html-validate's repo to fix the rule that's mistaken so hopefully we'll be unblocked soon 🥳 In the meantime, I'd welcome a first look from anyone in @alphagov/design-system-developers on the technical side of things. There might be small tweaks for the design, but would be good to know if everything looks OK 😊 |
35b5b02 to
7e96525
Compare
| createButton() { | ||
| const $button = document.createElement('button') | ||
| $button.classList.add('govuk-service-navigation__link') | ||
| $button.classList.add('app-mobile-navigation-section__button') | ||
| // Ensure no whitespace coming from the server rendered Service Navigation | ||
| // link gets into the button as it would mess the underline on hover | ||
| $button.textContent = this.$root.textContent.trim() | ||
| $button.setAttribute('aria-expanded', 'false') | ||
| $button.hidden = true | ||
|
|
||
| return $button | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question Wondering if this would be better implemented as a getter that caches its result, doing the same for the subnav? Logic behind it would be to avoid the createXYZ methods, but that might not be that much of a gain 🤔
get $button() {
if (!this._$button) {
const $button = document.createElement('button')
$button.classList.add('govuk-service-navigation__link')
$button.classList.add('app-mobile-navigation-section__button')
// Ensure no whitespace coming from the server rendered Service Navigation
// link gets into the button as it would mess the underline on hover
$button.textContent = this.$root.textContent.trim()
$button.setAttribute('aria-expanded', 'false')
$button.hidden = true
this._$button = $button;
}
return this._button;
}7e96525 to
9020aab
Compare
9020aab to
91d1a61
Compare
mia-allers-gds
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bf52b3a to
535e8ea
Compare
24ceac1 to
3a99b89
Compare
|
Looks good to me |
owenatgov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few little comments. Looking solid otherwise!
| font: inherit; | ||
| text-align: left; | ||
|
|
||
| // Add some extra affordance for mouse users |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extremely pithy point: is this comment necessary? I'm not sure what else this could be for.
| @@ -0,0 +1,43 @@ | |||
| {% macro mobileNavigationItem(params) %} | |||
| {% set current = true if params.pagePermalink and (params.pagePermalink == params.item.url) else false %} | |||
| {% set active = params.active if 'active' in params else (true if params.pagePermalink and params.pagePermalink.startsWith(params.item.url) else false) %} | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come this can't be if params.active?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that needs some explanation... and maybe a little rework on my part. params.active is there to override the default computed in the macro so that the first item of the subnav (eg. 'Components overview') is never 'active' as it would visually show the 'active' state when navigating a page of the subnav (eg. 'Button').
I'll rename the parameter to something more suitable (eg. ignoreActive) and leave a little comment as well.
36degrees
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little bit nervous about just how much we're overriding from the service navigation component on mobile – I'm concerned that we make changes to the component in GOV.UK Frontend that break the custom implementation here and don't notice. I don't think we really pay much attention to what the site looks like on mobile when e.g. updating GOV.UK Frontend.
I'm not sure what the solution to that is though – we could for example fork the component, but that does somewhat defeat the point of the exercise!
Maybe we should be considering introducing visual regression tests to the site at some point in the future 🤔
A couple of other things that I've noticed:
- the co-authored by trailer on 60d0508 doesn't look right
- a lot of comments seem to be wrapped semi-randomly, though I think I might be the only person who's bothered by this!
| }) | ||
|
|
||
| describe('when JavaScript is unavailable or fails', () => { | ||
| beforeEach(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to repeat this for each test or is it enough to use beforeAll and do it once at the start of the describe block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will need to investigate when Jest tears down pages between tests, but if it doesn't we could use beforeAll.
| }) | ||
|
|
||
| describe('when JavaScript is available', () => { | ||
| beforeEach(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to repeat this for each test or is it enough to use beforeAll and do it once at the start of the describe block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably do need this to be beforeEach because some of the nested describe blocks take us to other pages.
But the way the tests are structured makes this hard to follow – it's not particuarly clear for example which page the tests in the User interactions describe block are running on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a think at how to clarify that. Could always move the goTo at the start of the tests rather than in beforeEach/All to make it clearer what they run on 😊
| }) | ||
|
|
||
| describe('On a section root', () => { | ||
| beforeEach(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to repeat this for each test or is it enough to use beforeAll and do it once at the start of the describe block?
| }) | ||
|
|
||
| describe('In a page within a section', () => { | ||
| beforeEach(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to repeat this for each test or is it enough to use beforeAll and do it once at the start of the describe block?
That's a fair point. Visual regression tests sound a good shout (opening a components page and opening the menu would allow us to check that the subnav renders OK, including the active section and item).
Whoops, muscle-memory took over 😓 Thanks for spotting it!
I'll have a quick look as I edit things :) |
aab0862 to
4d0916a
Compare
|
I think I've gone through all the comments, hopefully:
|
4d0916a to
122eca3
Compare
Ports the code of #4368 for the rendering of the subnavigation of each item of the Service Nav in a `<template>` element which will then be used by JavaScript. Co-Authored-By: [email protected]
Instantiate one component per section of the navigation to easily group the toggle button and subnavigation it reveals Co-Authored-By: [email protected]
As the mobile navigation is only available when JavaScript is loaded, and gets shown/hidden through the `hidden` HTML attribute, styles do not need to be gated by a media query. As the links live withing the Service Navigation, we can reuse its `govuk-service-navigation__link` styles for the interactive elements (subnavigation toggle and links) Co-Authored-By: [email protected]
Include the fix that makes `<template>` tags correctly handled by `element-permitted-content`. https://gitlab.com/html-validate/html-validate/-/issues/305
122eca3 to
9dbcff5
Compare


Ports the code of #4368, splitting implementation into individual commits for the template, JavaScript and CSS. As a high level overview, the PR enhances the Service Navigation to provide the same accordion behaviour we have on the current navigation on mobile.
It does so by rendering inside each of the Service Navigation link a
<template>tag with the markup of the subnavigation for that section of the site. That template is then picked up by a newMobileNavigationSectionJavaScript component, instantiated for each link.The component injects the content of the template on the page, as well as a
<button>that'll let users toggle the visibility of the subnavigatio. It is also responsible for hiding the original link from the Service Navigation on mobile, and hiding the button and subnavigation on wider viewports. This allows the CSS to not rely on media queries for its styling.In more details this PR:
_mobile-navigation.njkpartial responsible for rendering the subnavigation for each item of the Service Navigation_navigation.njkpartial where the Service Navigation is renderedMobileNavigationSectionJavaScript component for enhancing the markup, toggling the subnavigation and controling its visibility based on the viewport