Skip to content

Commit dd473a3

Browse files
authored
Merge pull request #5206 from alphagov/service-navigation-component
Service navigation component
2 parents 3362ddf + 414298b commit dd473a3

20 files changed

+1488
-1
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ For advice on how to use these release notes see [our guidance on staying up to
44

55
## Unreleased
66

7+
### New features
8+
9+
#### Make it easier to navigate complex services with the Service navigation component
10+
11+
We've added a new [Service navigation component](https://design-system.service.gov.uk/components/service-navigation/) to help users to navigate services with multiple top-level sections. This replaces the navigation functions of the Header component, which will be deprecated in a future release of GOV.UK Frontend.
12+
13+
This component includes some features we consider experimental. We intend to iterate these features in response to user feedback. These are:
14+
15+
- moving the service name from the Header to the Service navigation
16+
- providing slots for injecting custom HTML into specified locations within the component
17+
18+
We introduced this change in [pull request #5206: Service navigation component](https://github.com/alphagov/govuk-frontend/pull/5206).
19+
720
## v5.5.0 (Feature release)
821

922
To install this version with npm, run `npm install [email protected]`. You can also find more information about [how to stay up to date](https://frontend.design-system.service.gov.uk/staying-up-to-date/#updating-to-the-latest-version) in our documentation.

packages/govuk-frontend/src/govuk-prototype-kit/govuk-prototype-kit.config.unit.test.mjs

+4
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ describe('GOV.UK Prototype Kit config', () => {
152152
importFrom: 'govuk/components/select/macro.njk',
153153
macroName: 'govukSelect'
154154
},
155+
{
156+
importFrom: 'govuk/components/service-navigation/macro.njk',
157+
macroName: 'govukServiceNavigation'
158+
},
155159
{
156160
importFrom: 'govuk/components/skip-link/macro.njk',
157161
macroName: 'govukSkipLink'

packages/govuk-frontend/src/govuk/all.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export { Header } from './components/header/header.mjs'
99
export { NotificationBanner } from './components/notification-banner/notification-banner.mjs'
1010
export { PasswordInput } from './components/password-input/password-input.mjs'
1111
export { Radios } from './components/radios/radios.mjs'
12+
export { ServiceNavigation } from './components/service-navigation/service-navigation.mjs'
1213
export { SkipLink } from './components/skip-link/skip-link.mjs'
1314
export { Tabs } from './components/tabs/tabs.mjs'
1415
export { initAll, createAll } from './init.mjs'

packages/govuk-frontend/src/govuk/all.puppeteer.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe('GOV.UK Frontend', () => {
6060
'NotificationBanner',
6161
'PasswordInput',
6262
'Radios',
63+
'ServiceNavigation',
6364
'SkipLink',
6465
'Tabs'
6566
])

packages/govuk-frontend/src/govuk/components/_index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
@import "phase-banner/index";
2828
@import "radios/index";
2929
@import "select/index";
30+
@import "service-navigation/index";
3031
@import "skip-link/index";
3132
@import "summary-list/index";
3233
@import "table/index";

packages/govuk-frontend/src/govuk/components/header/_index.scss

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@
3838
border-bottom: $govuk-header-border-width solid $govuk-header-border-color;
3939
}
4040

41+
.govuk-header--full-width-border {
42+
border-bottom-color: $govuk-header-border-color;
43+
44+
.govuk-header__container {
45+
border-bottom-color: transparent;
46+
}
47+
}
48+
4149
.govuk-header__logotype {
4250
display: inline-block;
4351
position: relative;

packages/govuk-frontend/src/govuk/components/header/header.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ examples:
247247
- href: '#3'
248248
text: Navigation item 3
249249

250+
- name: with full width border
251+
description: Makes the header's bottom border full width without affecting the header's content.
252+
options:
253+
classes: govuk-header--full-width-border
254+
productName: Product Name
255+
250256
- name: navigation item with html
251257
options:
252258
serviceName: Service Name
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Service navigation
2+
3+
## Installation
4+
5+
See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component.
6+
7+
## Guidance and Examples
8+
9+
Find out when to use the Service navigation component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/service-navigation).
10+
11+
## Component options
12+
13+
Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text.
14+
15+
See [options table](https://design-system.service.gov.uk/components/service-navigation/#options-service-navigation-example) for details.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
@include govuk-exports("govuk/component/service-navigation") {
2+
$govuk-service-navigation-active-link-border-width: govuk-spacing(1);
3+
$govuk-service-navigation-background: $govuk-canvas-background-colour;
4+
$govuk-service-navigation-border-colour: $govuk-border-colour;
5+
6+
// We make the link colour a little darker than normal here so that it has
7+
// better perceptual contrast with the navigation background.
8+
$govuk-service-navigation-link-colour: govuk-shade($govuk-link-colour, 10%);
9+
10+
.govuk-service-navigation {
11+
border-bottom: 1px solid $govuk-service-navigation-border-colour;
12+
background-color: $govuk-service-navigation-background;
13+
}
14+
15+
.govuk-service-navigation__container {
16+
display: flex;
17+
flex-direction: column;
18+
align-items: start;
19+
20+
@include govuk-media-query($from: tablet) {
21+
flex-direction: row;
22+
flex-wrap: wrap;
23+
}
24+
}
25+
26+
// These styles are shared between nav items and the service name, they
27+
// ensure that both of them remain vertically aligned with one another
28+
.govuk-service-navigation__item,
29+
.govuk-service-navigation__service-name {
30+
position: relative;
31+
margin: govuk-spacing(2) 0;
32+
border: 0 solid $govuk-service-navigation-link-colour;
33+
34+
@include govuk-media-query($from: tablet) {
35+
margin-top: 0;
36+
margin-bottom: 0;
37+
padding: govuk-spacing(4) 0;
38+
39+
&:not(:last-child) {
40+
@include govuk-responsive-margin(6, $direction: right);
41+
}
42+
}
43+
}
44+
45+
.govuk-service-navigation__item--active {
46+
@include govuk-media-query($until: tablet) {
47+
// Negative offset the left margin so we can place a current page indicator
48+
// to the left without misaligning the list item text.
49+
margin-left: ((govuk-spacing(2) + $govuk-service-navigation-active-link-border-width) * -1);
50+
padding-left: govuk-spacing(2);
51+
border-left-width: $govuk-service-navigation-active-link-border-width;
52+
}
53+
54+
@include govuk-media-query($from: tablet) {
55+
padding-bottom: govuk-spacing(4) - $govuk-service-navigation-active-link-border-width;
56+
border-bottom-width: $govuk-service-navigation-active-link-border-width;
57+
}
58+
}
59+
60+
.govuk-service-navigation__link {
61+
@include govuk-link-common;
62+
@include govuk-link-style-no-underline;
63+
@include govuk-link-style-no-visited-state;
64+
65+
&:not(:hover):not(:focus) {
66+
// We set the colour here as we don't want to override the hover or
67+
// focus colours
68+
color: $govuk-service-navigation-link-colour;
69+
}
70+
}
71+
72+
//
73+
// Service name specific code
74+
//
75+
76+
.govuk-service-navigation__service-name {
77+
@include govuk-font($size: 19, $weight: bold);
78+
}
79+
80+
// Annoyingly this requires a compound selector in order to overcome the
81+
// specificity of the other link colour override we're doing
82+
.govuk-service-navigation__service-name .govuk-service-navigation__link {
83+
@include govuk-link-style-text;
84+
}
85+
86+
//
87+
// Navigation list specific code
88+
//
89+
90+
.govuk-service-navigation__toggle {
91+
@include govuk-font($size: 19, $weight: bold);
92+
display: inline-flex;
93+
margin: 0 0 govuk-spacing(2);
94+
padding: 0;
95+
border: 0;
96+
color: $govuk-service-navigation-link-colour;
97+
background: none;
98+
word-break: break-all;
99+
cursor: pointer;
100+
align-items: center;
101+
102+
&:focus {
103+
@include govuk-focused-text;
104+
}
105+
106+
&::after {
107+
@include govuk-shape-arrow($direction: down, $base: 10px, $display: inline-block);
108+
content: "";
109+
margin-left: govuk-spacing(1);
110+
}
111+
112+
&[aria-expanded="true"]::after {
113+
@include govuk-shape-arrow($direction: up, $base: 10px, $display: inline-block);
114+
}
115+
116+
// Ensure the button stays hidden if the hidden attribute is present
117+
&[hidden] {
118+
display: none;
119+
}
120+
}
121+
122+
.govuk-service-navigation__list {
123+
@include govuk-font($size: 19);
124+
margin: 0;
125+
margin-bottom: govuk-spacing(3);
126+
padding: 0;
127+
list-style: none;
128+
129+
// Make the navigation list a flexbox. Doing so resolves a couple of
130+
// accessibility problems caused by the list items being inline-blocks:
131+
// - Removes the extra whitespace from between each list item that screen
132+
// readers would pointlessly announce.
133+
// - Fixes an NVDA issue in Firefox and Chrome <= 124 where it would read
134+
// all of the links as a run-on sentence.
135+
@include govuk-media-query($from: tablet) {
136+
display: flex;
137+
flex-wrap: wrap;
138+
margin-bottom: 0;
139+
140+
// However... IE11 totally trips over flexbox and doesn't wrap anything,
141+
// making all of the items into a single, horizontally scrolling row,
142+
// which is no good. This CSS hack removes the flexbox definition for
143+
// IE 10 & 11, reverting it to the flawed, but OK, non-flexbox version.
144+
//
145+
// CSS hack taken from https://stackoverflow.com/questions/11173106/apply-style-only-on-ie#answer-36448860
146+
// which also includes an explanation of why this works
147+
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
148+
display: block;
149+
}
150+
}
151+
}
152+
153+
// This is a <strong> element that is used as a fallback mechanism for
154+
// visually indicating the current page in scenarios where CSS isn't
155+
// available. We don't actually want it to be bold normally, so set it to
156+
// inherit the parent font-weight.
157+
.govuk-service-navigation__active-fallback {
158+
font-weight: inherit;
159+
}
160+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@import "../../base";
2+
@import "./index";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { axe, render } from '@govuk-frontend/helpers/puppeteer'
2+
import { getExamples } from '@govuk-frontend/lib/components'
3+
4+
describe('/components/service-navigation', () => {
5+
let axeRules
6+
7+
beforeAll(() => {
8+
axeRules = {
9+
/**
10+
* Ignore 'Element has insufficient color contrast' for WCAG Level AAA
11+
*/
12+
'color-contrast-enhanced': { enabled: false }
13+
}
14+
})
15+
16+
describe('component examples', () => {
17+
it('passes accessibility tests', async () => {
18+
const examples = await getExamples('service-navigation')
19+
20+
// Remove the 'with no options set' example from being tested, as the
21+
// component doesn't output anything in that scenario.
22+
delete examples['with no options set']
23+
24+
for (const exampleName in examples) {
25+
await render(page, 'service-navigation', examples[exampleName])
26+
await expect(axe(page, axeRules)).resolves.toHaveNoViolations()
27+
}
28+
}, 120000)
29+
})
30+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{% macro govukServiceNavigation(params) %}
2+
{%- include "./template.njk" -%}
3+
{% endmacro %}

0 commit comments

Comments
 (0)