Skip to content
This repository has been archived by the owner on Jul 30, 2019. It is now read-only.

Consider adding headings to allowed content in <label> element #1270

Closed
36degrees opened this issue Mar 1, 2018 · 10 comments
Closed

Consider adding headings to allowed content in <label> element #1270

36degrees opened this issue Mar 1, 2018 · 10 comments
Assignees

Comments

@36degrees
Copy link
Member

In #724 the spec was changed to allow headings as permitted children of legends, but this same change was not also extended to labels.

This means that including a heading as part of a legend is valid, but including a heading as part of a label is not.

Is there any reason why the label should not behave the same as the legend in this regard?

I am happy to put together a more detailed case for this change, and test behaviour in browsers and assistive technologies, but wanted to open an issue early to make sure there wasn't something obvious I'd missed that would prevent this from even being an option.

Thanks.

@chaals
Copy link
Collaborator

chaals commented Mar 1, 2018

I think explaining the use case (i.e. concrete examples where you would use this) and testing that it doesn't break stuff are the first steps. If you are happy to do that, I don't know of any reason to hold back.

(Something to test is what happens, e.g. in a screen reader, when you have a heading in a label, and how it interacts with ARIA headings...)

@scottaohara
Copy link
Member

Agreed with @chaals. I'd be interested to understand more about why this would be a necessary use case and why, if a label did in fact need to double as a heading, the following valid markup pattern wouldn't suffice:

<h3>
  <label for="input">
    test
  </label>
</h3>
<input type="text" id="input">

@36degrees
Copy link
Member Author

Thanks, both!

The specific use case we're trying to cater for here is where the user is presented with a page with a single question on it, where the question is both the heading for the page and also the label/legend for the field/fieldset.

For example, in this example, the question 'What is your date of birth?' is marked up as a legend with a heading inside it. This was a change we made in June 2017 after a lot of research by a colleague.

govuk-design-system-production cloudapps digital_patterns_question-pages_default_index html

This works great, but only because of the change made in #724 which permits headings to exist within legends.

Of course, if the question does not require a fieldset then instead we need to make the heading a label:

govuk-design-system-production cloudapps digital_patterns_question-pages_postcode_index html

In this case, our current approach is exactly what @scottaohara suggested – rather than putting the heading inside the label, we invert it and put the label inside the heading.

However, we've identified two issues with this:

Firstly, we are currently re-implementing this as part of a design system where everything is styled using explicit classes and we're finding that the label class is overriding the heading styling, and so the resulting element looks like a label:

<h1 class="govuk-heading-xl"><label class="govuk-c-label">test</label></h1>

I recognise that this is not insurmountable – one possible solution we've come up with is to provide a modifier for the label that makes it look like a heading:

<h1><label class="govuk-c-label govuk-c-label--heading-xl">test</label></h1>

However, this introduces extra complexity for developers where I think it could be avoided. Allowing headings inside labels would allow us to use the same approach in both cases, rather than developers having to remember that the heading should go inside a legend with the normal heading class, but outside a label without a class and with a modifier on the label. I strongly suspect that what will happen is that a lot of developers will end up putting the headings inside the <label> anyway, because it works and that's what they.

Secondly, where the field has a 'hint' or an error message, we associate them with the field by including them inside the label. This means that the hint and error message also become part of the H1 in this case. This isn't an issue with the fieldset, where the hint and error message are inside the label but outside of the H1. We are currently exploring whether we can move these out of the label and associate them with aria-describedby instead, which may make this a non-issue, but we need to do further testing to make sure this isn't going to case any issues with assistive technologies.

@scottaohara
Copy link
Member

scottaohara commented Mar 1, 2018

@36degrees, if I'm understanding you correctly, this seems to be more of a specificity issue with your design system than a markup issue, or problem with the spec?

I know I don't have full context here, but I would not expect a label to also be a page heading.

I also wouldn't expect a label to have a label class on it, if it were meant to look like a heading it was contained within. If everything is styled via classes, then having the heading with its appropriate class, and a label without a class applied to it, should then fix the styling specificity issue you're encountering?

Here is a codepen in how I understand your issue and outlining how I'd expect to mitigate this.

@36degrees
Copy link
Member Author

if I'm understanding you correctly, this seems to be more of a specificity issue with your design system than a markup issue, or problem with the spec?

Yep, that's a fair enough comment. But to me it feels like it's a workaround and that in this case the spec might not be right.

In #724, the history of the legend element was reported as:

This history FWIW is that HTML4 restricted legend to inline/phrasing and we just propagated that because as far as I remember at least nobody til now ever proposed loosening it.

I would like to know if the same holds true for labels – is it just that this is a hangover from HTML4 and no-one has ever proposed loosening it? If so, I think there is merit in making labels and legends behave in a similar way.

Conversely, if this is by design – if there is a good reason why why legends can contain headings but labels cannot, then it would be really useful to understand what that reason is.

I know I don't have full context here, but I would not expect a label to also be a page heading.

I think the second screenshot above, which demonstrates our 'one thing per page' format is a good example of a scenario where you would want to do exactly that. It was previously implemented as a visually hidden H1 with a visible label, but after a lot of testing this was changed as a result of feedback from our accessibility community – as described in some detail here.

@scottaohara
Copy link
Member

scottaohara commented Mar 1, 2018

Appreciate the additional context @36degrees.

Definitely something to discuss further. Thanks again for raising the issue.

@36degrees
Copy link
Member Author

Hi,

I've built a couple of basic test cases for the 'current implementation' (label inside heading) and the proposal (heading inside label) and used these to capture screenshots and test with assistive technologies.

I haven't found to cause concern – it seems to behave as expected with everything I tested.

Browser Screenshots

Android Google Nexus 9

Heading inside label (proposed behaviour)

android_google-nexus-9_5 0_portrait_heading_inside_label

Label inside heading (current behaviour)

android_google-nexus-9_5 0_portrait_label_inside_heading

Android Samsung Galaxy S5

Heading inside label (proposed behaviour)

android_samsung-galaxy-s5_4 4_portrait_heading_inside_label

Label inside heading (current behaviour)

android_samsung-galaxy-s5_4 4_portrait_label_inside_heading

iPad 3rd Generation (iOS 6.0)

Heading inside label (proposed behaviour)

ios_ipad-3rd- 6 0 _6 0_portrait_heading_inside_label

Label inside heading (current behaviour)

ios_ipad-3rd- 6 0 _6 0_portrait_label_inside_heading

iPad Mini (iOS 7.0)

Heading inside label (proposed behaviour)

ios_ipad-mini_7 0_portrait_heading_inside_label

Label inside heading (current behaviour)

ios_ipad-mini_7 0_portrait_label_inside_heading

iPad Mini 2 (iOS 8.3)

Heading inside label (proposed behaviour)

ios_ipad-mini-2_8 3_portrait_heading_inside_label

Label inside heading (current behaviour)

ios_ipad-mini-2_8 3_portrait_label_inside_heading

Safari 9.1 (Mac OS X El Capitan)

Heading inside label (proposed behaviour)

macelc_safari_9 1_heading_inside_label

Label inside heading (current behaviour)

macelc_safari_9 1_label_inside_heading

Safari 8.0 (Mac OS X Yosemite)

Heading inside label (proposed behaviour)

macyos_safari_8 0_heading_inside_label

Label inside heading (current behaviour)

macyos_safari_8 0_label_inside_heading

IE8 (Windows 7)

Heading inside label (proposed behaviour)

win7_ie_8 0_heading_inside_label

Label inside heading (current behaviour)

win7_ie_8 0_label_inside_heading

IE9 (Windows 7)

Heading inside label (proposed behaviour)

win7_ie_9 0_heading_inside_label

Label inside heading (current behaviour)

win7_ie_9 0_label_inside_heading

IE10 (Windows 8)

Heading inside label (proposed behaviour)

win8_ie_10 0_heading_inside_label

Label inside heading (current behaviour)

win8_ie_10 0_label_inside_heading

IE11 (Windows 8)

Heading inside label (proposed behaviour)

win8 1_ie_11 0_heading_inside_label

Label inside heading (current behaviour)

win8 1_ie_11 0_label_inside_heading

Chrome 48 (Windows 10)

Heading inside label (proposed behaviour)

win10_chrome_48 0_heading_inside_label

Label inside heading (current behaviour)

win10_chrome_48 0_label_inside_heading

Chrome 49 (Windows 10)

Heading inside label (proposed behaviour)

win10_chrome_49 0_heading_inside_label

Label inside heading (current behaviour)

win10_chrome_49 0_label_inside_heading

Chrome 50 (Windows 10)

Heading inside label (proposed behaviour)

win10_chrome_50 0_heading_inside_label

Label inside heading (current behaviour)

win10_chrome_50 0_label_inside_heading

Edge 15 (Windows 10)

Heading inside label (proposed behaviour)

win10_edge_15 0_heading_inside_label

Label inside heading (current behaviour)

win10_edge_15 0_label_inside_heading

Firefox 43 (Windows 10)

Heading inside label (proposed behaviour)

win10_firefox_43 0_heading_inside_label

Label inside heading (current behaviour)

win10_firefox_43 0_label_inside_heading

Firefox 44 (Windows 10)

Heading inside label (proposed behaviour)

win10_firefox_44 0_heading_inside_label

Label inside heading (current behaviour)

win10_firefox_44 0_label_inside_heading

Firefox 45 (Windows 10)

Heading inside label (proposed behaviour)

win10_firefox_45 0_heading_inside_label

Label inside heading (current behaviour)

win10_firefox_45 0_label_inside_heading

Assistive technologies

I've tested with the combinations of assistive technologies and browsers as recommended by the GOV.UK Service Manual – I'm happy to test further combinations if it helps to build confidence in this change.

JAWS 17, IE11, Windows 10

On page load

Headings inside labels test case, Headings inside labels test case, Headings inside labels test case

Page has one heading and no links. Headings inside labels test case, Heading level 1: What is your home postcode? Edit, continue button, continue"

(This behaviour is the same with the current implementation ('inverse' test case), including the duplication of the page title etc.

Using list of all headings (JAWS + F6)

JAWS lists one heading, What is your home postcode? : 1, 1 of 1.

[Selecting the heading, JAWS announces:]

"Heading level 1, what is your home postcode? what is your home postcode? Heading level 1"

(This duplication of the heading happens in other places – with the existing implementation and e.g. the H1 on the GOV.UK homepage)

Moving through headings using 'h' shortcut

JAWS focusses the heading and announces "What is your home postcode, heading level 1"

[Tab to field from there:]

What is your home postcode? edit, type of text.

ZoomText 10.1, IE11, Windows 10

Using Reader speech mode

Clicking in the text field, ZoomText announces "What is your home postcode?"

Using AppRdr

Clicking on the start of the heading, ZoomText announces "What is your home postcode? Continue, end of document".

This is the same behaviour as with the inverse test case.

Dragon NaturallySpeaking 13, IE11, Windows 10

Able to focus and fill in form field using voice prompts:

  • "Click what is your home postcode?"
  • "Click postcode"
NVDA 2017.4, Mozilla Firefox 52.7.2, Windows 10

Clickable heading level 1, what is your home postcode

(The current implementation reads "Heading level 1 clickable, what is your home postcode")

Edit has autocomplete, button continue

Navigating backwards from the input using Shift-H:

"Clickable what is your home postcode, heading level 1"

(The current implementation reads "Clickable what is your home postcode, heading level 1")

Navigating through form fields using F:

"What is your home postcode, edit has autocomplete"

VoiceOver with Safari 11, OS El Capitan

Navigating through the page from the top

Voiceover announces "Start interacting with Headings inside labels test case, HTML content, What is your home postcode? group"

[Navigating to the next element using VO + Right arrow]

Voiceover announces "What is your home postcode? edit text"

[Navigating back to the previous heading using VO + Cmd + Shift + H]

Voiceover announces "Heading level 1, What is your home postcode?"

Using the rotor

Heading "What is your home post code?" appears in headings list in rotor

Navigating to heading using the rotor focusses the cursor on the heading

Form control "What is your home post code? edit text" appears in form control list in rotor.

Navigating to form control from the rotor focusses the form field and VoiceOver announces "What is your home postcode? edit text"

VoiceOver, Safari with iOS 11.2.6 (iPhone X)

[Swiping right from top of page until the form field is focussed]

Voiceover announces "What is your home postcode? Text field. Double tap to edit."

[Headings selected in rotor menu.]

Voiceover announces "1 heading".

From top of document, "What is your home postcode? Heading level 1"

@36degrees
Copy link
Member Author

What are the next steps that need to be done to make progress on this?

@chaals
Copy link
Collaborator

chaals commented Mar 28, 2018

@36degrees

What are the next steps that need to be done to make progress on this?

At a minimum, the ping you just made. More effective would be writing a Pull Request that made the change to the spec.

The logic and the use case seem reasonable, and it is hard to imagine what this would actually break...

Ping @sideshowbarker

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants