Skip to content
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

Make it easier to add a hint or an error message to a fieldset #1281

Closed
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,12 @@ changelog](./docs/contributing/versioning.md#updating-changelog).

([PR #1371](https://github.com/alphagov/govuk-frontend/pull/1371))

- Remove duplicate form field markup from each macro

All form fields are now wrapped in `govukFormGroup()` to generate the appropriate hint, error message, fieldset and legend (or label).

([PR #1281](https://github.com/alphagov/govuk-frontend/pull/1281))

🔧 Fixes:

- Removed adjustments that were needed for v1 Transport
Expand Down
1 change: 1 addition & 0 deletions src/components/_all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@import "fieldset/fieldset";
@import "file-upload/file-upload";
@import "footer/footer";
@import "form-group/form-group";
@import "hint/hint";
@import "header/header";
@import "input/input";
Expand Down
63 changes: 18 additions & 45 deletions src/components/checkboxes/template.njk
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% from "../error-message/macro.njk" import govukErrorMessage -%}
{% from "../fieldset/macro.njk" import govukFieldset %}
{% from "../form-group/macro.njk" import govukFormGroup %}
{% from "../hint/macro.njk" import govukHint %}
{% from "../label/macro.njk" import govukLabel %}

Expand All @@ -11,8 +10,14 @@
aria-describedby – for example hints or error messages -#}
{% set describedBy = params.describedBy if params.describedBy else "" %}
{% if params.fieldset.describedBy %}
{% set describedBy = params.fieldset.describedBy %}
{% set describedBy = params.fieldset.describedBy %}
{% endif %}
{%- if params.hint -%}
{%- set describedBy = (describedBy + ' ' + idPrefix + "-hint") | trim -%}
{%- endif -%}
{%- if params.errorMessage -%}
{%- set describedBy = (describedBy + ' ' + idPrefix + "-error") | trim -%}
{%- endif -%}

{% set isConditional = false %}
{% for item in params.items %}
Expand All @@ -22,33 +27,16 @@
{% endfor %}

{#- fieldset is false by default -#}
{% set hasFieldset = true if params.fieldset else false %}
{%- set hasFieldset = true if params.fieldset else false -%}

{#- Capture the HTML so we can optionally nest it in a fieldset -#}
{% set innerHtml %}
{% if params.hint %}
{% set hintId = idPrefix + '-hint' %}
{% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %}
{{ govukHint({
id: hintId,
classes: params.hint.classes,
attributes: params.hint.attributes,
html: params.hint.html,
text: params.hint.text
}) | indent(2) | trim }}
{% endif %}
{% if params.errorMessage %}
{% set errorId = idPrefix + '-error' %}
{% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %}
{{ govukErrorMessage({
id: errorId,
classes: params.errorMessage.classes,
attributes: params.errorMessage.attributes,
html: params.errorMessage.html,
text: params.errorMessage.text,
visuallyHiddenText: params.errorMessage.visuallyHiddenText
}) | indent(2) | trim }}
{% endif %}
{% call govukFormGroup({
id: idPrefix,
fieldset: params.fieldset,
hint: params.hint,
label: params.label,
errorMessage: params.errorMessage,
formGroup: params.formGroup
}) %}
<div class="govuk-checkboxes {%- if params.classes %} {{ params.classes }}{% endif %}"
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %}
{%- if isConditional %} data-module="govuk-checkboxes"{% endif -%}>
Expand Down Expand Up @@ -101,19 +89,4 @@
{% endif %}
{% endfor %}
</div>
{% endset -%}

<div class="govuk-form-group {%- if params.errorMessage %} govuk-form-group--error{% endif %} {%- if params.formGroup.classes %} {{ params.formGroup.classes }}{% endif %}">
{% if params.fieldset %}
{% call govukFieldset({
describedBy: describedBy,
classes: params.fieldset.classes,
attributes: params.fieldset.attributes,
legend: params.fieldset.legend
}) %}
{{ innerHtml | trim | safe }}
{% endcall %}
{% else %}
{{ innerHtml | trim | safe }}
{% endif %}
</div>
{% endcall %}
97 changes: 29 additions & 68 deletions src/components/date-input/template.njk
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
{% from "../error-message/macro.njk" import govukErrorMessage -%}
{% from "../fieldset/macro.njk" import govukFieldset %}
{% from "../hint/macro.njk" import govukHint %}
{% from "../input/macro.njk" import govukInput %}

{#- a record of other elements that we need to associate with the input using
aria-describedby – for example hints or error messages -#}
{% set describedBy = params.fieldset.describedBy if params.fieldset.describedBy else "" %}
{% from "../form-group/macro.njk" import govukFormGroup %}
{% from "../label/macro.njk" import govukLabel %}

{% if params.items %}
{% set dateInputItems = params.items %}
Expand All @@ -26,72 +20,39 @@
] %}
{% endif %}

{#- Capture the HTML so we can optionally nest it in a fieldset -#}
{% set innerHtml %}
{% if params.hint %}
{% set hintId = params.id + "-hint" %}
{% set describedBy = describedBy + " " + hintId if describedBy else hintId %}
{{ govukHint({
id: hintId,
classes: params.hint.classes,
attributes: params.hint.attributes,
html: params.hint.html,
text: params.hint.text
}) | indent(2) | trim }}
{% endif %}
{% if params.errorMessage %}
{% set errorId = params.id + "-error" %}
{% set describedBy = describedBy + " " + errorId if describedBy else errorId %}
{{ govukErrorMessage({
id: errorId,
classes: params.errorMessage.classes,
attributes: params.errorMessage.attributes,
html: params.errorMessage.html,
text: params.errorMessage.text,
visuallyHiddenText: params.errorMessage.visuallyHiddenText
}) | indent(2) | trim }}
{% endif %}
<div class="govuk-date-input {%- if params.classes %} {{ params.classes }}{% endif %}"
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}
{%- if params.id %} id="{{ params.id }}"{% endif %}>
{% for item in dateInputItems %}
<div class="govuk-date-input__item">
{{ govukInput({
label: {
text: item.label if item.label else item.name | capitalize,
classes: "govuk-date-input__label"
},
id: item.id if item.id else (params.id + "-" + item.name),
classes: "govuk-date-input__input " + (item.classes if item.classes),
name: (params.namePrefix + "-" + item.name) if params.namePrefix else item.name,
value: item.value,
type: "number",
autocomplete: item.autocomplete,
pattern: item.pattern if item.pattern else "[0-9]*",
attributes: item.attributes
}) | indent(6) | trim }}
</div>
{% endfor %}
</div>
{% endset %}

<div class="govuk-form-group {%- if params.errorMessage %} govuk-form-group--error{% endif %} {%- if params.formGroup.classes %} {{ params.formGroup.classes }}{% endif %}">
{% if params.fieldset %}
{#- We override the fieldset's role to 'group' because otherwise JAWS does not
announce the description for a fieldset comprised of text inputs, but
adding the role to the fieldset always makes the output overly verbose for
radio buttons or checkboxes. -#}
{% call govukFieldset({
describedBy: describedBy,
{% call govukFormGroup({
id: params.id,
fieldset: {
describedBy: params.fieldset.describedBy,
classes: params.fieldset.classes,
attributes: {
role: "group"
},
legend: params.fieldset.legend
}) %}
{{ innerHtml | trim | safe }}
{% endcall %}
{% else %}
{{ innerHtml | trim | safe }}
{% endif %}
</div>
},
hint: params.hint,
errorMessage: params.errorMessage,
formGroup: params.formGroup
}) %}
<div class="govuk-date-input {%- if params.classes %} {{ params.classes }}{% endif %}"
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}
{%- if params.id %} id="{{ params.id }}"{% endif %}>
{% for item in dateInputItems %}
<div class="govuk-date-input__item">
{{ govukLabel({
text: item.label if item.label else item.name | capitalize,
classes: "govuk-date-input__label",
for: item.id if item.id else (params.id + "-" + item.name)
}) | indent(4) | trim }}
<input class="govuk-input govuk-date-input__input {%- if item.classes %} {{ item.classes }}{% endif %}" id="{{ item.id if item.id else (params.id + '-' + item.name) }}" name="{{ (params.namePrefix + '-' + item.name) if params.namePrefix else item.name }}" type="number" pattern="{{ item.pattern if item.pattern else '[0-9]*' }}"
{%- if item.value %} value="{{ item.value }}"{% endif %}
{%- if item.autocomplete %} autocomplete="{{ item.autocomplete}}"{% endif %}
{%- for attribute, value in item.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}>
</div>
{% endfor %}
</div>
{% endcall %}
47 changes: 11 additions & 36 deletions src/components/file-upload/template.njk
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
{% from "../error-message/macro.njk" import govukErrorMessage -%}
{% from "../hint/macro.njk" import govukHint %}
{% from "../label/macro.njk" import govukLabel %}
{% from "../form-group/macro.njk" import govukFormGroup -%}

{#- a record of other elements that we need to associate with the input using
aria-describedby – for example hints or error messages -#}
{% set describedBy = params.describedBy if params.describedBy else "" %}
<div class="govuk-form-group {%- if params.errorMessage %} govuk-form-group--error{% endif %} {%- if params.formGroup.classes %} {{ params.formGroup.classes }}{% endif %}">
{{ govukLabel({
html: params.label.html,
text: params.label.text,
classes: params.label.classes,
isPageHeading: params.label.isPageHeading,
attributes: params.label.attributes,
for: params.id
}) | indent(2) | trim }}
{% if params.hint %}
{% set hintId = params.id + '-hint' %}
{% set describedBy = describedBy + ' ' + hintId if describedBy else hintId %}
{{ govukHint({
id: hintId,
classes: params.hint.classes,
attributes: params.hint.attributes,
html: params.hint.html,
text: params.hint.text
}) | indent(2) | trim }}
{% endif %}
{% if params.errorMessage %}
{% set errorId = params.id + '-error' %}
{% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %}
{{ govukErrorMessage({
id: errorId,
classes: params.errorMessage.classes,
attributes: params.errorMessage.attributes,
html: params.errorMessage.html,
text: params.errorMessage.text,
visuallyHiddenText: params.errorMessage.visuallyHiddenText
}) | indent(2) | trim }}
{% endif %}

{%- if params.hint -%}
{%- set describedBy = (describedBy + ' ' + params.id + "-hint") | trim -%}
{%- endif -%}
{%- if params.errorMessage -%}
{%- set describedBy = (describedBy + ' ' + params.id + "-error") | trim -%}
{%- endif -%}

{% call govukFormGroup(params) %}
<input class="govuk-file-upload {%- if params.classes %} {{ params.classes }}{% endif %} {%- if params.errorMessage %} govuk-file-upload--error{% endif %}" id="{{ params.id }}" name="{{ params.name }}" type="file"
{%- if params.value %} value="{{ params.value }}"{% endif %}
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}>
</div>
{% endcall %}
15 changes: 15 additions & 0 deletions src/components/form-group/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Form group

## 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 form group component in your service in the [GOV.UK Design System](https://design-system.service.gov.uk/components/form-group).

## 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/form-group/#options-example-default) for details.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@import "../settings/all";
@import "../tools/all";
@import "../helpers/all";
@import "../../settings/all";
@import "../../tools/all";
@import "../../helpers/all";

@include govuk-exports("govuk/objects/form-group") {
@include govuk-exports("govuk/component/form-group") {

.govuk-form-group {
@include govuk-clearfix;
Expand Down
66 changes: 66 additions & 0 deletions src/components/form-group/form-group.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
params:
- name: id
type: string
required: true
description: The id of the input
- name: fieldset
type: object
required: false
description: Options for the fieldset component (e.g. legend).
isComponent: true
- name: hint
type: object
required: false
description: Options for the hint component.
isComponent: true
- name: label
type: object
required: false
description: Options for the label component if no fieldset is provided.
isComponent: true
- name: errorMessage
type: object
required: false
description: Options for the errorMessage component.
isComponent: true
- name: formGroup
type: object
required: false
description: Options for the form-group wrapper.
params:
- name: classes
type: string
required: false
description: Classes to add to the form group (e.g. to show error state for the whole group)
- name: caller
type: nunjucks-block
required: false
description: Not strictly a parameter but [Nunjucks code convention](https://mozilla.github.io/nunjucks/templating.html#call). Using a `call` block enables you to 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 will need to wrap the entire form group component in a `call` block.

examples:
- name: default
data:
id: address
label:
text: What is your address?
- name: with label as page heading
data:
id: address-heading
label:
text: What is your address?
classes: govuk-label--xl
isPageHeading: true
- name: with fieldset legend
data:
id: address-fieldset
fieldset:
legend:
text: What is your address?
- name: with fieldset legend as page heading
data:
id: address-fieldset-heading
fieldset:
legend:
text: What is your address?
classes: govuk-fieldset__legend--xl
isPageHeading: true
3 changes: 3 additions & 0 deletions src/components/form-group/macro.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% macro govukFormGroup(params) %}
{%- include "./template.njk" -%}
{% endmacro %}
Loading