From 447218b782f5f222113e9d36034ee2929bea4766 Mon Sep 17 00:00:00 2001 From: Owen Jones Date: Wed, 1 Jul 2026 11:58:34 +0100 Subject: [PATCH 1/4] Add feedback component --- .../govuk-prototype-kit.config.unit.test.mjs | 4 + .../src/govuk/components/_index.import.scss | 1 + .../src/govuk/components/_index.scss | 1 + .../src/govuk/components/feedback/README.md | 15 +++ .../components/feedback/_feedback.import.scss | 5 + .../components/feedback/_index.import.scss | 7 ++ .../src/govuk/components/feedback/_index.scss | 4 + .../src/govuk/components/feedback/_mixin.scss | 42 ++++++++ .../feedback/accessibility.puppeteer.test.mjs | 28 ++++++ .../govuk/components/feedback/feedback.yaml | 95 +++++++++++++++++++ .../src/govuk/components/feedback/macro.njk | 3 + .../govuk/components/feedback/template.njk | 24 +++++ .../components/feedback/template.test.js | 86 +++++++++++++++++ 13 files changed, 315 insertions(+) create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/README.md create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/_feedback.import.scss create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/_index.import.scss create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/_index.scss create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/_mixin.scss create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/accessibility.puppeteer.test.mjs create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/feedback.yaml create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/macro.njk create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/template.njk create mode 100644 packages/govuk-frontend/src/govuk/components/feedback/template.test.js diff --git a/packages/govuk-frontend/src/govuk-prototype-kit/govuk-prototype-kit.config.unit.test.mjs b/packages/govuk-frontend/src/govuk-prototype-kit/govuk-prototype-kit.config.unit.test.mjs index a1772e87e6..47bb952d25 100644 --- a/packages/govuk-frontend/src/govuk-prototype-kit/govuk-prototype-kit.config.unit.test.mjs +++ b/packages/govuk-frontend/src/govuk-prototype-kit/govuk-prototype-kit.config.unit.test.mjs @@ -92,6 +92,10 @@ describe('GOV.UK Prototype Kit config', () => { importFrom: 'govuk/components/exit-this-page/macro.njk', macroName: 'govukExitThisPage' }, + { + importFrom: 'govuk/components/feedback/macro.njk', + macroName: 'govukFeedback' + }, { importFrom: 'govuk/components/fieldset/macro.njk', macroName: 'govukFieldset' diff --git a/packages/govuk-frontend/src/govuk/components/_index.import.scss b/packages/govuk-frontend/src/govuk/components/_index.import.scss index cffa9acca7..7cf2c49728 100644 --- a/packages/govuk-frontend/src/govuk/components/_index.import.scss +++ b/packages/govuk-frontend/src/govuk/components/_index.import.scss @@ -10,6 +10,7 @@ @import "error-message"; @import "error-summary"; @import "exit-this-page"; +@import "feedback"; @import "fieldset"; @import "file-upload"; @import "footer"; diff --git a/packages/govuk-frontend/src/govuk/components/_index.scss b/packages/govuk-frontend/src/govuk/components/_index.scss index 9e829d6a96..db63f7977c 100644 --- a/packages/govuk-frontend/src/govuk/components/_index.scss +++ b/packages/govuk-frontend/src/govuk/components/_index.scss @@ -10,6 +10,7 @@ @use "error-message"; @use "error-summary"; @use "exit-this-page"; +@use "feedback"; @use "fieldset"; @use "file-upload"; @use "footer"; diff --git a/packages/govuk-frontend/src/govuk/components/feedback/README.md b/packages/govuk-frontend/src/govuk/components/feedback/README.md new file mode 100644 index 0000000000..9d3d8ee6d3 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/README.md @@ -0,0 +1,15 @@ +# Feedback + +## Installation + +See the [main README quick start guide](https://github.com/alphagov/govuk-frontend#quick-start) for how to install this component. + +## Guidance and Examples + +Find out when to use the Feedback component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/feedback). + +## Component options + +Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text. + +See [options table](https://design-system.service.gov.uk/components/feedback/#options-feedback-example) for details. diff --git a/packages/govuk-frontend/src/govuk/components/feedback/_feedback.import.scss b/packages/govuk-frontend/src/govuk/components/feedback/_feedback.import.scss new file mode 100644 index 0000000000..02429ab082 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/_feedback.import.scss @@ -0,0 +1,5 @@ +@use "../../settings/warnings--internal"; + +@include warnings--internal.component-scss-file-warning("feedback"); + +@import "index"; diff --git a/packages/govuk-frontend/src/govuk/components/feedback/_index.import.scss b/packages/govuk-frontend/src/govuk/components/feedback/_index.import.scss new file mode 100644 index 0000000000..01b0188e23 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/_index.import.scss @@ -0,0 +1,7 @@ +@use "mixin"; + +@import "../../base"; + +@include govuk-exports("govuk/component/feedback") { + @include mixin.styles; +} diff --git a/packages/govuk-frontend/src/govuk/components/feedback/_index.scss b/packages/govuk-frontend/src/govuk/components/feedback/_index.scss new file mode 100644 index 0000000000..9e35774853 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/_index.scss @@ -0,0 +1,4 @@ +@use "../../custom-properties"; +@use "mixin"; + +@include mixin.styles; diff --git a/packages/govuk-frontend/src/govuk/components/feedback/_mixin.scss b/packages/govuk-frontend/src/govuk/components/feedback/_mixin.scss new file mode 100644 index 0000000000..87960d9aed --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/_mixin.scss @@ -0,0 +1,42 @@ +@use "../../base"; + +/// @access private +@mixin styles { + .govuk-feedback { + box-sizing: border-box; + // Tie left/right padding to page gutter as it stretches across the whole + // screen on smaller screens + padding: base.govuk-spacing(4) base.$govuk-gutter-half base.govuk-spacing(5); + border-top: 1px solid; + border-color: base.govuk-functional-colour("brand"); + background-color: base.govuk-functional-colour("surface-background"); + + @media #{base.govuk-from-breakpoint(tablet)} { + padding-right: base.govuk-spacing(4); + padding-left: base.govuk-spacing(4); + } + + // Override $govuk-width-container's left and right margin as we want Feedback + // to go across the whole screen on smaller screens + @media #{base.govuk-until-breakpoint(tablet)} { + margin-right: 0; + margin-left: 0; + } + } + + .govuk-feedback__title { + @include base.govuk-font($size: 24, $weight: bold); + margin-top: 0; + color: base.govuk-functional-colour(text); + @include base.govuk-responsive-margin(1, "bottom"); + } + + // Removes the bottom margin from the final child element eg: a paragraph + // + // Feedback body doesn't have any opinions about typography. Instead we defer + // to users to use typography classes in their input, or apply a `govuk-body` + // paragraph for if users pass `text`. + .govuk-feedback__body > :last-child { + margin-bottom: 0; + } +} diff --git a/packages/govuk-frontend/src/govuk/components/feedback/accessibility.puppeteer.test.mjs b/packages/govuk-frontend/src/govuk/components/feedback/accessibility.puppeteer.test.mjs new file mode 100644 index 0000000000..26d56867a7 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/accessibility.puppeteer.test.mjs @@ -0,0 +1,28 @@ +import { axe, render } from '@govuk-frontend/helpers/puppeteer' +import { getExamples } from '@govuk-frontend/lib/components' + +describe('/components/feedback', () => { + let axeRules + + beforeAll(() => { + axeRules = { + /** + * Ignore 'Element has insufficient color contrast' for WCAG Level AAA + * + * Affects links on 'surface background' functional colour + */ + 'color-contrast-enhanced': { enabled: false } + } + }) + + describe('component examples', () => { + it('passes accessibility tests', async () => { + const examples = await getExamples('feedback') + + for (const exampleName in examples) { + await render(page, 'feedback', examples[exampleName]) + await expect(axe(page, axeRules)).resolves.toHaveNoViolations() + } + }, 120000) + }) +}) diff --git a/packages/govuk-frontend/src/govuk/components/feedback/feedback.yaml b/packages/govuk-frontend/src/govuk/components/feedback/feedback.yaml new file mode 100644 index 0000000000..8ff63f0279 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/feedback.yaml @@ -0,0 +1,95 @@ +params: + - name: titleText + type: string + required: true + description: Text to use within the title of the Feedback component. If `titleHtml` is provided, the `titleText` option will be ignored. + - name: titleHtml + type: string + required: true + description: HTML to use within the title of the Feedback component. If `titleHtml` is provided, the `titleText` option will be ignored. + - name: headingLevel + type: integer + required: false + description: Heading level, from `1` to `6`. Default is `2`. + - name: text + type: string + required: true + description: Text to use within the Feedback component content. If `html` is provided, the `text` option will be ignored. + - name: html + type: string + required: true + description: HTML to use within the Feedback component content. If `html` is provided, the `text` option will be ignored. + - name: caller + type: nunjucks-block + required: false + description: Not strictly a parameter but a [Nunjucks code convention](https://mozilla.github.io/nunjucks/templating.html#call). Using a `call` block lets you call a macro with all the text inside the tag. This is helpful if you want to pass a lot of content into a macro. To use it, you'll need to wrap the entire Feedback component in a `call` block. + - name: classes + type: string + required: false + description: Classes to add to the Feedback component container. + - name: attributes + type: object + required: false + description: HTML attributes (for example, data attributes) to add to the Feedback component container. + +examples: + - name: default + screenshot: true + options: + titleText: Help us improve this service + html: | +

Tell us about your experience using this service. Give us your feedback

+ + - name: silly example + description: In reality we'd recommend users only use the default example but this is to illustrate if a service team decides they want to add a lot of content + options: + titleText: Help us improve this service + html: | +

Tell us about your experience using this service.

+

Click this cool link to give us your feedback.

+

There's another paragraph here.

+ + + # Hidden examples are not shown in the review app, but are used for tests and HTML fixtures + - name: html in title + hidden: true + options: + titleHtml: Help us improve this cool service + html: | +

Tell us about your experience using this service. Give us your feedback

+ + - name: custom heading level + hidden: true + options: + titleText: Help us improve this service + headingLevel: 3 + html: | +

Tell us about your experience using this service. Give us your feedback

+ + - name: html in text options + hidden: true + options: + titleText: Help us improve this cool service + text: Tell us about your experience using this cool service + + - name: classes + hidden: true + options: + titleText: Help us improve this service + html: | +

Tell us about your experience using this service. Give us your feedback

+ classes: my-first-class my-second-class + + - name: attributes + hidden: true + options: + titleText: Help us improve this service + html: | +

Tell us about your experience using this service. Give us your feedback

+ attributes: + first-attribute: first + second-attribute: second diff --git a/packages/govuk-frontend/src/govuk/components/feedback/macro.njk b/packages/govuk-frontend/src/govuk/components/feedback/macro.njk new file mode 100644 index 0000000000..c95d0f94b3 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/macro.njk @@ -0,0 +1,3 @@ +{% macro govukFeedback(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/packages/govuk-frontend/src/govuk/components/feedback/template.njk b/packages/govuk-frontend/src/govuk/components/feedback/template.njk new file mode 100644 index 0000000000..c1ed7420b2 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/template.njk @@ -0,0 +1,24 @@ +{% from "../../macros/attributes.njk" import govukAttributes -%} + +{% set headingLevel = params.headingLevel if params.headingLevel else 2 -%} + +
+
+
+ + {{ params.titleHtml | safe if params.titleHtml else params.titleText }} + + {% if caller or params.html or params.text %} +
+ {% if caller or params.html %} + {{ caller() if caller else params.html | safe | trim | indent(4) }} + {% elif params.text %} +

+ {{ params.text | trim | indent(6) }} +

+ {% endif %} +
+ {% endif %} +
+
+
diff --git a/packages/govuk-frontend/src/govuk/components/feedback/template.test.js b/packages/govuk-frontend/src/govuk/components/feedback/template.test.js new file mode 100644 index 0000000000..a8fa309c34 --- /dev/null +++ b/packages/govuk-frontend/src/govuk/components/feedback/template.test.js @@ -0,0 +1,86 @@ +const { render } = require('@govuk-frontend/helpers/nunjucks') +const { getExamples } = require('@govuk-frontend/lib/components') + +describe('Feedback', () => { + let examples + + beforeAll(async () => { + examples = await getExamples('feedback') + }) + + describe('default example', () => { + it('renders title text', () => { + const $ = render('feedback', examples.default) + const feedbackTitle = $('.govuk-feedback__title').text().trim() + + expect(feedbackTitle).toBe('Help us improve this service') + }) + + it('renders title as h2 (as the default heading level)', () => { + const $ = render('feedback', examples.default) + const feedbackTitleHeadingLevel = $('.govuk-feedback__title')[0].name + + expect(feedbackTitleHeadingLevel).toBe('h2') + }) + + it('renders body text', () => { + const $ = render('feedback', examples.default) + const feedbackBody = $('.govuk-feedback__body').html().trim() + + expect(feedbackBody).toBe( + '

Tell us about your experience using this service. Give us your feedback

' + ) + }) + }) + + describe('custom options', () => { + it('renders title html', () => { + const $ = render('feedback', examples['html in title']) + const feedbackTitle = $('.govuk-feedback__title').html().trim() + + expect(feedbackTitle).toBe('Help us improve this cool service') + }) + + it('renders title with a custom heading level', () => { + const $ = render('feedback', examples['custom heading level']) + const feedbackTitleHeadingLevel = $('.govuk-feedback__title')[0].name + + expect(feedbackTitleHeadingLevel).toBe('h3') + }) + + it('escapes html passed to titleText', () => { + const $ = render('feedback', examples['html in text options']) + const feedbackTitle = $('.govuk-feedback__title').html().trim() + + expect(feedbackTitle).toBe( + 'Help us improve this <em>cool</em> service' + ) + }) + + it('escapes html passed to text', () => { + const $ = render('feedback', examples['html in text options']) + const feedbackBody = $('.govuk-feedback__body > .govuk-body') + .html() + .trim() + + expect(feedbackBody).toBe( + 'Tell us about your experience using this <em>cool</em> service' + ) + }) + + it('allows additional classes to be added to the component', () => { + const $ = render('feedback', examples.classes) + + const $component = $('.govuk-feedback') + expect($component.hasClass('my-first-class my-second-class')).toBeTruthy() + }) + + it('allows additional attributes to be added to the component', () => { + const $ = render('feedback', examples.attributes) + + const $component = $('.govuk-feedback') + expect($component.attr('first-attribute')).toBe('first') + expect($component.attr('second-attribute')).toBe('second') + }) + }) +}) From fe66702a72307de2191e736d357bc547dc2cef2d Mon Sep 17 00:00:00 2001 From: Owen Jones Date: Wed, 1 Jul 2026 11:59:13 +0100 Subject: [PATCH 2/4] Add feedback to "have you changed your name" example --- .../have-you-changed-your-name/confirm.njk | 11 +++++++++++ .../have-you-changed-your-name/index.njk | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/confirm.njk b/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/confirm.njk index bdf7bec202..3509b3fd9b 100644 --- a/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/confirm.njk +++ b/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/confirm.njk @@ -1,6 +1,7 @@ {% extends "layouts/full-page-example.njk" %} {% from "govuk/components/panel/macro.njk" import govukPanel %} +{% from "govuk/components/feedback/macro.njk" import govukFeedback %} {% set pageTitle = "Thank you for confirming if you have changed your name" %} {% block pageTitle %}{{ pageTitle }} - GOV.UK{% endblock %} @@ -14,3 +15,13 @@ {% endblock %} + +{% block footerStart %} + {% call govukFeedback({ + titleText: "Help us improve this service" + }) %} +

+ Tell us about your experience using this service. Give us your feedback +

+ {% endcall %} +{% endblock %} diff --git a/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/index.njk b/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/index.njk index 3629cd4af6..c65b08e8a7 100644 --- a/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/index.njk +++ b/packages/govuk-frontend-review/src/views/full-page-examples/have-you-changed-your-name/index.njk @@ -16,6 +16,7 @@ scenario: | {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} {% from "govuk/components/radios/macro.njk" import govukRadios %} {% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/feedback/macro.njk" import govukFeedback %} {% set pageTitle = example.title %} {% block pageTitle %}{{ "Error: " if errorSummary | length }}{{ pageTitle }} - GOV.UK{% endblock %} @@ -70,3 +71,13 @@ scenario: | {% endblock %} + +{% block footerStart %} + {% call govukFeedback({ + titleText: "Help us improve this service" + }) %} +

+ Tell us about your experience using this service. Give us your feedback +

+ {% endcall %} +{% endblock %} From 1bb3c47352614ed62d06598811d0ce99884e0efa Mon Sep 17 00:00:00 2001 From: Owen Jones Date: Wed, 1 Jul 2026 11:59:26 +0100 Subject: [PATCH 3/4] Add Feedback to Translated examples --- .../src/views/examples/translated/index.njk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/govuk-frontend-review/src/views/examples/translated/index.njk b/packages/govuk-frontend-review/src/views/examples/translated/index.njk index b7d7b888dd..4cbec701bb 100644 --- a/packages/govuk-frontend-review/src/views/examples/translated/index.njk +++ b/packages/govuk-frontend-review/src/views/examples/translated/index.njk @@ -12,6 +12,7 @@ {% from "govuk/components/error-message/macro.njk" import govukErrorMessage %} {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} {% from "govuk/components/exit-this-page/macro.njk" import govukExitThisPage %} +{% from "govuk/components/feedback/macro.njk" import govukFeedback %} {% from "govuk/components/file-upload/macro.njk" import govukFileUpload %} {% from "govuk/components/footer/macro.njk" import govukFooter %} {% from "govuk/components/header/macro.njk" import govukHeader %} @@ -332,6 +333,14 @@ ] }) }} + {% call govukFeedback({ + titleText: "Helpwch ni i wella'r gwasanaeth hwn" + }) %} +

+ Dywedwch wrthym am eich profiad o ddefnyddio'r gwasanaeth hwn. Rhowch eich adborth i ni +

+ {% endcall %} + {{ govukFileUpload({ id: "file-upload-1", name: "file-upload-1", From bec43221683a4f9c9ec1bb9d89233134814d9208 Mon Sep 17 00:00:00 2001 From: Owen Jones Date: Wed, 1 Jul 2026 12:06:33 +0100 Subject: [PATCH 4/4] Add changelog entry for feedback --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c28d995d7..c5d2f9b361 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ For advice on how to use these release notes, see [our guidance on staying up to ### New features +#### Use the Feedback component to collect feedback from users on your service + +We've added the [Feedback component](https://design-system.service.gov.uk/components/feedback/) to help services collect feedback from their users throughout their service. + +This was added in [pull request #7232: Add Feedback component](https://github.com/alphagov/govuk-frontend/pull/7232). + #### You can now pass `day`, `month`, `year`, `error` and `values` options to the Date input component We've updated the Date input component to add the following Nunjucks options: