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

"For example, it is incorrect to use hidden to h..." #4904

Open
jnurthen opened this issue Sep 11, 2019 · 42 comments
Open

"For example, it is incorrect to use hidden to h..." #4904

jnurthen opened this issue Sep 11, 2019 · 42 comments

Comments

@jnurthen
Copy link
Member

https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute:the-hidden-attribute-5

For example, it is incorrect to use hidden to hide panels in a tabbed dialog, because the tabbed interface is merely a kind of overflow presentation — one could equally well just show all the form controls in one big page with a scrollbar.

This is confusing. Having content on non-visible tab pages which are not hidden from screen readers would normally cause accessibility issues. I suggest removing this example.

@domenic
Copy link
Member

domenic commented Sep 18, 2019

Can you explain more why this is confusing? In particular, which part of the spec do you disagree with? This example conveys the semantics of the hidden attribute and the authoring guidance we want to encourage for it.

@ZoeBijl
Copy link

ZoeBijl commented Sep 18, 2019

This is related to this aria-practices bug and the APG’s Tabs code example. In our code example we use the hidden-attribute to hide the inactive [role=tabpanel]s. This results in behaviour which is similar to that of macOS and Windows tabs—which is what we want.

Is there a reason why this should be discouraged?

@domenic
Copy link
Member

domenic commented Sep 18, 2019

Yes; the quoted section of the spec explains why this is not an appropriate use for the hidden attribute.

@ZoeBijl
Copy link

ZoeBijl commented Sep 18, 2019

But the quoted section says the direct opposite of what the ARIA APG recommends. So there’s a discrepancy between our recommendations. What is the reasoning behind the HTML spec’s recommendation?

@domenic
Copy link
Member

domenic commented Sep 18, 2019

Hmm, again, I think the spec covers this pretty well, with the portion quoted in the OP (starting with "because").

@ZoeBijl
Copy link

ZoeBijl commented Sep 20, 2019

The HTML spec says the following about the hidden-attribute:

When specified on an element, it indicates that the element is not yet, or is no longer, directly relevant to the page's current state, or that it is being used to declare content to be reused by other parts of the page as opposed to being directly accessed by the user.

From an accessibility point of view an inactive tabpanel is not relevant to the page’s current state. We don’t want people to access things that are in an inactive tabpanel and are thus not visible. This approach has been proven in native platforms such as macOS and Windows where you also can’t access the content in inactive tabpanels.

The ARIA WG’s advice to developers is to apply a tabbed interface via progressive enhancement. If JS were to fail all would be tabbed content would be visible|available. If CSS were to fail the hidden-attribute would make sure the tabbed interface would still work as intended.

As a developer the definition of the hidden-attribute confuses me. I would think it’s interchangeable with applying display: none to an element. Unfortunately I don’t have much data on how other developers think about this. Would it be possible to change the definition of the semantics and relax the conformance rules for the hidden-attribute to match how web developers use this attribute?

Adding @zcorpan who might be a good person to liaise in this situation.

@domenic
Copy link
Member

domenic commented Sep 20, 2019

From an accessibility point of view an inactive tabpanel is not relevant to the page’s current state. We don’t want people to access things that are in an inactive tabpanel and are thus not visible. This approach has been proven in native platforms such as macOS and Windows where you also can’t access the content in inactive tabpanels.

I think you are using a different definition of "not relevant" than the specification is using. The specification tries to clarify what it means via examples such as the one posted in the OP.

I agree that you don't want people accessing the inactive tabpanel. display: none is a fine way to do that, without bringing along the irrelevance semantics of the hidden="" attribute.

If CSS were to fail the hidden-attribute would make sure the tabbed interface would still work as intended.

This is not true, at least, not in any CSS user agent (i.e. all of them I'm aware of). The hidden attribute is defined to work via CSS. I am not aware of any browsers where CSS can "fail", or how that might happen, but if it does so, then the spec requires that the hidden attribute also stop hiding things.

As a developer the definition of the hidden-attribute confuses me. I would think it’s interchangeable with applying display: none to an element.

Nope. The specification tries to be very clear about this, via a series of explanations and examples, such as the one you quoted, or the one in the OP. The hidden attribute is semantic, not stylistic; it conveys irrelevance, which is not the same as the stylistic (and also accessibility/interaction) properties conveyed via display: none. Another way of stating this is that the hidden attribute is about application state, not UI state.

In particular, the hidden attribute is applicable in a subset of the cases where display: none is applicable. (This is a good thing, as otherwise it would be pointless---we don't go around just defining HTML attributes which correspond 1:1 with CSS property/value pairs!)

We could try to make this clearer, for example, by explicitly stating the subset relationship to display: none, e.g. expanding the example you quote to say that display: none is more appropriate for such situations instead of relying on developers to know that there are other ways of hiding content from visual presentation and interaction.

@zcorpan
Copy link
Member

zcorpan commented Sep 21, 2019

I think there are two separate points @ZoeBijl

  • the semantic distinction is a thing the spec maintains but web developers are unaware of this, and when they learn about it still fail to understand the point of the distinction. I suppose this is similar to whether the em and i elements should have different semantics, or just mean "italics". Is the distinction helpful to anyone or is it just wasting web developers' time? (For e.g. headings, I think it is clear that the semantics are helpful.)
  • if we keep the irrelevance semantics of hidden, is the spec correct about the tab interface example? That is, are there cases where it is appropriate to use hidden for the inactive tab panels?

@ZoeBijl
Copy link

ZoeBijl commented Sep 21, 2019

That is, are there cases where it is appropriate to use hidden for the inactive tab panels?

One example I could think of is a tabbed interface where some of the tabpanels are dynamically loaded. Meaning: the tabpanel’s content gets loaded when you activate the associated tab. Does that align with what the spec tells me?

Some of the wording in the HTML spec seems to indicate that it’s fine to expose all of the content that’s in inactive tabpanels to people. This is incorrect and, if nothing else, I think we should correct this. I think @domenic’s suggestion of adding a line about display: none could be a good way to do this.


What follows I write as a developer and not as an accessibility engineer. Because frankly this doesn’t impact accessibility at all.

It would be very interesting to have a better understanding of how developers use the hidden-attribute. Is there a way for us to figure this out? As a developer myself the distinction made in the HTML specification makes no sense to me. I understand that there is one but am not convinced it’s doing more good than harm.

I realise that I’m but one data point in a sea of developers. But I’ve always used the hidden-attribute as an easy way to hide elements when I would’ve otherwise had to rely on setting a class (which means I also have to create a class). To me it’s a much more aesthetically pleasing way of going about it.

@domenic, you say that “we don't go around just defining HTML attributes which correspond 1:1 with CSS property/value pairs!” I think that’s probably a good thing in most cases. Similarly, the ARIA WG doesn’t go around and create aria-attributes that map 1:1 to all HTML (and other host languages) attributes. But we make exceptions where it makes sense or there is a need for it. In my opinion this is such a case.

I’d like to reiterate that I don’t write this as an accessibility but as a developer that has apparently been using the hidden-attribute wrong for the last seven odd years. In that regard I’m more frustrated with myself than with the specification. Which is why it would be good to know if there are others like me that weren’t aware of this distinction and have also been using it wrong.

@annevk
Copy link
Member

annevk commented Sep 24, 2019

I don't really follow @domenic. If elsewhere it's found that you do want to hide such dialog panels from all users, why would HTML suggest you don't want to be doing that? That does seem confusing to me.

@domenic
Copy link
Member

domenic commented Sep 25, 2019

If elsewhere it's found that you do want to hide such dialog panels from all users, why would HTML suggest you don't want to be doing that?

Hiding from the user is easy. You do that with display: none.

Conveying that it is irrelevant to the application's current state is different from hiding from the user. As the spec states, tab pages which are currently hidden from the user are not irrelevant to the application's current state. It's just a UX choice to present them in tabs, which is best conveyed with presentational CSS, not semantic HTML.

@scottaohara
Copy link
Collaborator

scottaohara commented Sep 25, 2019

IMO it seems that both viewpoints are correct, but they're dependent on the way someone codes their tabbed interface.

Strictly speaking of a tabbed UI built with HTML (and css) alone, I would agree with Domenic's explanation of the hidden attribute here, and think it's important for developers to know when something should be hidden with CSS vs using the semantic attribute. If a series of links both navigated users to, and toggled the display of sections of a document, then it could stand to reason that the presentational CSS could be removed and all sections were exposed. IMO, this fits the example in question.

On the other hand, a tabbed interface using ARIA tab, tablist and tabpanel roles convey different semantics and expected functionality. With an ARIA tab widget typically only the currently selected tab's associated tabpanel should be exposed to users, and it's semantically important that the tabpanels that are not exposed are hidden. It would be unexpected for this to be reliant solely on presentational CSS, as it would be inappropriate for inactive panels to be exposed to users, resulting in a divergence of the conveyed semantics vs the actual presented content.

Regarding the example, might this be resolved by referring to a different type of component? e.g. steps within a multi-part form, rather than mentioning tabs at all to move away from this sort of confusion?

@alice
Copy link
Contributor

alice commented Sep 27, 2019

I also find the wording in the spec confusing.

In particular, I don't know that this is universally agreed:

the tabbed interface is merely a kind of overflow presentation — one could equally well just show all the form controls in one big page with a scrollbar.

I had a look at some modern[1] guidelines to see what they would say.

The Apple Human Interface Guidelines say:

A tab view presents multiple mutually exclusive panes of content in the same area.

And the Material Design Guidelines say:

Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.

Each tab should contain content that is distinct from other tabs in a set.

(Emphasis mine). I think this indicates that most users would not consider non-selected tabs to be directly relevant to the page's current state.

I gather that the spec language is intended to convey an example of the difference between visually hidden and hidden.

I think that's going to be a tricky distinction to make at the best of times, for all the usual reasons that visual semantics are practically always the only meaningful semantics from a user's point of view. In particular, there is a recurring debate around the extent to which styling should affect the accessibility tree, which IMO is founded on a misunderstanding of what "semantics" mean in this context.

This example in particular risks perpetuating a misunderstanding which could lead to a poorer experience for assistive technology users, so it doesn't seem justifiable to me to leave it in.

I think a better example might be able to be constructed from something like a print view which may include something like a watermark or a copyright statement which may not be relevant in a browser view.


[1] This was after spending some time on memory lane at http://hallofshame.gp.co.at/tabs.htm - I, too, remember when Windows XP was the new goodness.

@domenic
Copy link
Member

domenic commented Sep 27, 2019

I'm not OK with removing this example; I think it's important to convey the inappropriateness of the hidden attribute for this situation, to avoid snafus exactly like the ARIA guidelines work that uses hidden incorrectly. I think we should definitely expand it to clear up the misunderstanding and confusion that has grown up around it, e.g. explicitly contrasting with display: none as was discussed above, but I do not think we should remove or replace it.

In particular I think it will be really valuable to use this example to distinguish between accessibility/styling concerns (i.e., for users) and semantic concerns (in this case, primarily for web developers). display: none is ideal for the former, whereas hidden="" is intended for the latter. As @alice mentions, people often misunderstand what "semantics" mean in these kind of contexts, leading to issues like this one. So the more we can do to clarify that difference, the better.

I think this indicates that most users would not consider non-selected tabs to be directly relevant to the page's current state.

As the guidelines you quote mention, the tabs are about related functionality. They are all relevant to the page's current state---otherwise they wouldn't be grouped together in a tab control. That's true even if the inactive tabs are not relevant to the UI's current state, or to the user's current perception.

@alice
Copy link
Contributor

alice commented Sep 27, 2019

I don't think the hidden attribute is inappropriate in this situation, for the reasons I outlined above.

@domenic
Copy link
Member

domenic commented Sep 27, 2019

I understand that's your impression; I'm saying it doesn't match the specification, and we should update it to clarify, to the extent it's causing folks like yourself to think that.

@alice
Copy link
Contributor

alice commented Sep 27, 2019

What would the alternative presentation of a tabbed dialog be in which an inactive pane would be relevant?

@domenic
Copy link
Member

domenic commented Sep 27, 2019

The spec spells that out; you could style it in other ways such as a scrollbar. Different UI patterns don't affect application state; they are different ways of imposing UI state.

@alice
Copy link
Contributor

alice commented Sep 27, 2019

I cited several design guidelines which IMO made it clear that you would never actually restyle a tabbed interface as a scroll interface, because the tabs are mutually exclusive. That is what I'm basing my opinion that hidden is actually appropriately used for a tabbed interface on.

@domenic
Copy link
Member

domenic commented Sep 27, 2019

I understand that designers may not choose to design sites that way. That doesn't change the fact that ultimately hiding the contents of other tabs is a UI design pattern, not an application state management pattern.

Contrast this with the example usage of the hidden attribute in the spec, which uses it to hide a game behind a login screen. Hidden is used on the entire state of the application that is not currently relevant; it isn't used for simply something the user isn't looking at right now due to a UI design choice.

@alice
Copy link
Contributor

alice commented Sep 27, 2019

@scottaohara's example seemed like a better wording to me:

If a series of links both navigated users to, and toggled the display of sections of a document, then it could stand to reason that the presentational CSS could be removed and all sections were exposed. IMO, this fits the example in question.

This is, unlike the tabbed pane example, an example of non mutually exclusive sections of a document which may be viewed as one sequence or individually. That is, it really could reasonably be styled as a single section (as it would be if the user expanded all the sections).

An example of this would be an email thread in gmail, which allows expanding any/all of the previous emails in a thread.

In my experience, if people are pulling content for a tabbed view to the client before they are to be shown (which is obviously not always the case), it is for reasons of performance or convenience rather than because they are actually relevant to the page at the time they are pulled in. Given that in many cases the content for the inactive tab isn't even in the page, it seems like the tabbed pane example really isn't demonstrating the intended meaning.

@ZoeBijl
Copy link

ZoeBijl commented Sep 27, 2019

At this point multiple people have contributed different examples and explanations of why the hidden-attribute is appropriate for tabpanels. Yet, I’ve not seen any other evidence that this shouldn’t be the case. And pointing to the spec that we’re trying to change isn’t much help as is clear from the replies. Can you please explain what the impact is on users? That’s who were making this for in the end. I already outlined an example where using the hidden attribute could actually benefit a user. I’ve not yet heard examples of situations where it would harm them. Could you please explain that/provide examples? Thank you.

@domenic
Copy link
Member

domenic commented Sep 27, 2019

At this point multiple people have contributed different examples and explanations of why the hidden-attribute is appropriate for tabpanels

I don't think this is a fair statement. Multiple people have explained why they find the current text confusing. But that doesn't change the fact that the spec is pretty clear that it's not appropriate. Ultimately, the hidden attribute is defined by the spec, so it is not appropriate for tab panels. We should make the spec less confusing, but I object to changing its definition.

Can you please explain what the impact is on users?

Users aren't really at issue here; users are served just as much by display: none as by hidden="". Semantic HTML usage rarely has impact on users; users are instead impacted by things like accessibility mappings, visual presentation, and the like. But there is no difference between display: none and hidden="" in that regard, so this is purely a question of developer-facing semantics.

@LJWatson
Copy link

I'm inclined to agree that hidden isn't appropriate for a set of tabpanels because it breaks progressive enhancement unless the attribute has been applied progressively - and I don't know that the HTML spec is the place for that level of advice.

@alice
Copy link
Contributor

alice commented Sep 29, 2019

@LJWatson The original concern was that the spec is using tab panels specifically as an example of when not to use hidden, under any circumstances. It seems like your opinion is that it might be ok to use hidden, if applied progressively. Have I misunderstood that?

@LJWatson
Copy link

@alice no, you didn't misunderstand. Providing it's applied progressively, I think it should be fine to use hidden on a set of tabpanels.

The need to apply it progressively is critical though. If it's applied inline and the JavaScript that drives the functionality fails out, the hidden tabpanels will remain hidden, and that needs to be avoided.

@alice
Copy link
Contributor

alice commented Sep 30, 2019

@LJWatson

The need to apply it progressively is critical though. If it's applied inline and the JavaScript that drives the functionality fails out, the hidden tabpanels will remain hidden, and that needs to be avoided.

That seems to take the view (which @domenic advocates and I dispute) that you could always reasonably present the content in a set of tabpanels in a sequential manner (e.g. by concatenating the panels together).

I think this is true sometimes, but not always. I'm typing this in a panel with two tabs, where the other tab is a preview of the generated content; I could imagine a view where I see them both at the same time.

Conversely, if we imagined implementing a tabbed web browser in HTML, I wouldn't expect that there might be a situation in which we would want to see the contents of all the tabs concatenated together.

That's why I think the example is misleading and risks creating confusion for developers and, potentially, a poor experience for AT users. I think there is more nuance required than to simply say that the APG is wrong to recommend hidden for tab panels, and that the spec would be better served by a different example to illustrate the same point.

@domenic

Ultimately, the hidden attribute is defined by the spec, so it is not appropriate for tab panels. We should make the spec less confusing, but I object to changing its definition.

I don't quite follow this. Are you including the tab panel example as part of the definition? If not, I think it's still reasonable to question whether the example is an accurate representation of the definition, or represents a reasonable assertion about tab panels.

@LJWatson
Copy link

LJWatson commented Sep 30, 2019 via email

@ZoeBijl
Copy link

ZoeBijl commented Oct 1, 2019

@LJWatson I wouldn’t go as far as saying the APG is recommending an absolute. The hidden attribute isn’t mentioned in the tabs design pattern text nor is it mentioned in the attributes table on the tabs example page.

The attribute page does mention the following for the tabpanel role:

Is hidden unless its associated tab control is activated.

Other than using the hidden attribute in the example code the APG doesn’t recommend its usage nor say that’s the only way to do it. Perhaps we should clarify that in the APG. I’ll leave that for another time since that would depend on the resolution of this issue.


To clarify, I’m happy to change the tabs example to use display: none. That doesn’t take anything away from me thinking the advice that’s currently in the HTML spec is wrong. I think @alice provided good examples of different use cases.

If the HTML editors are set on keeping the tabs example I think we should at least change the example to mention it’s OK to use the hidden attribute when applied progressively. As has already been suggested by several people in this thread.

@zcorpan
Copy link
Member

zcorpan commented Oct 7, 2019

I think the "applied progressively" argument misses the point @domenic is making. Given the semantic definition of hidden, it makes no difference at all as to whether your use is appropriate depending on whether you apply the attribute in the markup or with JS.

It can make a difference for accessibility, but that's not the point.

It's like saying "the spec should say that tables are allowed to be used for layout if you specify role=presentation". While that can make it OK as far as accessibility goes, it's still not OK given the semantic definition of table -- it's only conforming to use table for data tables.

Similarly, it's only conforming to use the hidden attribute for things that are not currently relevant to the page's current state. There are other good reasons for wanting to hide things, but hidden is not meant to be a presentational feature.

@zcorpan
Copy link
Member

zcorpan commented Oct 7, 2019

The example in the spec is specifically about "tabbed dialog"

For example, it is incorrect to use hidden to hide panels in a tabbed dialog

It doesn't follow that it is incorrect to use hidden for all kinds of tab panels. For example, the Web game that the spec gives as a correct usage of hidden could use tabs to switch back to the login screen, and it would still be correct to use hidden.

I think at this point the spec can probably do a better job at explaining this:

  • hidden is a semantic attribute, not a presentational attribute.
  • Use display: none for presentational use cases (where content should be hidden from all users).
  • Tab panels can be used as a presentational design choice where the underlying semantic is "everything is relevant, just showing a subset right now" or "only this tab is currently relevant to the page's state", and it's the underlying semantic that dictates whether hidden is appropriate, not the choice of using tab panel.

@ZoeBijl
Copy link

ZoeBijl commented Oct 7, 2019

I’ve changed the APG’s tabs code example to use display: none to comply with the HTML spec’s definition of the hidden attribute.


With one issue down, I do think the spec text is confusing and suggests that it’s OK to expose non visible tab content to AT. Might I suggest we change it a little bit?

Current:

For example, it is incorrect to use hidden to hide panels in a tabbed dialog, because the tabbed interface is merely a kind of overflow presentation — one could equally well just show all the form controls in one big page with a scrollbar.

Proposal:

For example, it is incorrect to use hidden to hide panels in a tabbed dialog. Such overflow presentations should use display: none; to hide non-visible content from all users.

Short, to the point, and retaining the original intent.

@alice
Copy link
Contributor

alice commented Oct 7, 2019

It might also be worthwhile reconsidering this snippet:

... if something is marked hidden, it is hidden from all presentations, including, for instance, screen readers.

That seems to imply that the "tabbed dialog" example would be correctly marked up if it exposed the inactive tabs to screen reader users.

@ZoeBijl
Copy link

ZoeBijl commented Nov 11, 2019

Is there anything we can do to move this forward?

@domenic
Copy link
Member

domenic commented Nov 11, 2019

A pull request along the lines of #4904 (comment) would be the next step.

@Heydon
Copy link

Heydon commented Nov 21, 2019

Multiple people have explained why they find the current text confusing. But that doesn't change the fact that the spec is pretty clear that it's not appropriate.

The opposite of confusing is clear, so I find this a somewhat remarkable assertion.

I just wanted to add the implication of having to use display: none is that you need to know what the visible/unhidden display value is: flex, grid, inline-block, block, something else. With hidden, this is not an issue. It is better fit for purpose.

@domenic
Copy link
Member

domenic commented Nov 21, 2019

That isn't true.

.tab {
  display: flex;
}

.tab.inactive {
  display: none;
}

@Heydon
Copy link

Heydon commented Nov 22, 2019

That isn't true.

@domenic This contrived example illustrates exactly what I mean. A developer would have to either write or be aware of this CSS ahead of time. It's non-standard, and not a general solution.

hidden, on the other hand, can be applied arbitrarily, to any element, and without switching contexts. It's also less verbose (and presumably more performant).

elem.classList.toggle('inactive', isInactive);

elem.hidden = !elem.hidden

@ZoeBijl
Copy link

ZoeBijl commented Nov 22, 2019

A very similar bug was reported back in 2010: Bug 9438: several issues with the hidden attribute.

@thierryk
Copy link

thierryk commented May 23, 2021

hidden, on the other hand, can be applied arbitrarily, to any element, and without switching contexts

I agree, but then we could use a class for that:

.hidden {
  display: none;
}

Or using ARIA:

.hidden,
hidden,
[role="tabpanel"][aria-hidden="true"] {
  display: none;
}

As a side note, a widget could have its panels visually hidden but accessible to AT. I know that this would create a different problem since the widget would not be presented as a tabpanel to AT, but you see my point regarding semantics vs. presentation.

@LJWatson
Copy link

As a side note, a widget could have its panels visually hidden but accessible to AT. I know that this would create a different problem since the widget
would not be presented as a tabpanel to AT, but you see my point regarding semantics vs. presentation.

It really would cause problems, so I strongly suggest it isn't considered as an option.

People who use AT do not always work in isolation. Collaborating with other people and referencing content you believe to be present, but which is evidently not to the person you're collaborating with, is a remarkably awkward situation to be in.

Also, the convenience of the tabpanel interaction is just as relevant to AT users as it is everyone else, so offering different experiences is not a happy outcome either.

@thierryk
Copy link

Collaborating with other people and referencing content you believe to be present, but which is evidently not to the person you're collaborating with, is a remarkably awkward situation to be in.

I agree, and that's what I had in mind when I said that it would create a different problem.

Also, the convenience of the tabpanel interaction is just as relevant to AT users as it is everyone else, so offering different experiences is not a happy outcome either.

I understand that a different experience can be an issue regarding collaborating, etc. but to me, a tabpanel is a more complex mental model than a simple succession of headings and their related content so I "assume" that the latter should be simpler/easier to navigate for most SR users. More importantly, it would be possible for these users to search and access the entire document rather than just what's visually exposed (a big caveat in my opinion when it comes to tabpanels and accordions). With these widgets, the content is always/usually relevant to the document, it is just not exposed because of purely visual (?) UI considerations. That's a price we ask all users to pay even though those widgets have been designed for sighted users.

Also, in the case of a tabpanel based on headings, the fact that their role is changed to tab means they are not as easily "discoverable" as if they were presented as headings (please tell me if I'm wrong here).

To me, the 2 main concerns with an hybrid approach (which would allow AT to access the entire content of these widgets) are:

  • different experiences (as you mentioned)
  • sighted-keyboard users would have to go through every single focusable elements inside the "visually-hidden" panels

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

10 participants