openui / open-ui

Maintain an open standard for UI and promote its adherence and adoption.
https://open-ui.org
Other
3.5k stars 186 forks source link

A standard spoiler / content-warning mechanism #772

Open jimmyfrasche opened 1 year ago

jimmyfrasche commented 1 year ago

A spoiler / content-warning mechanism is used to hide content not all readers may wish to read or at least not yet. In addition to spoilers and content warnings, this can be used to tag the answer to a question in a tutorial or on study site to let the reader attempt to solve it themselves before checking their work. For brevity, I will only refer to this as spoilers from now on.

This is a common pattern for community-oriented sites. It is a common enough pattern to have a section on wikipedia, for whatever that's worth: https://en.wikipedia.org/wiki/Spoiler_(media)#Website_policies_and_features

A spoiler is open or closed and user interaction toggles this state. A closed spoiler obscures (but does not collapse) its children. Generally this is by making it all black to resemble redacted text though sometimes a heavy background-blur is used for spoilered images. When closed its obscured content is inert. Sometimes there is a reason provided to tag book vs. movie spoilers or to explain the nature of the content warning to let the reader decide.

This should be standardized for two reasons

There are three paths to standardization

details/summary immediately comes up in all previous discussions but does not work for a multitude of reasons:

where details/summary fails

  • It is a block level element so it cannot be used to spoiler inline text. Even with display: inline the use of a details tag will autoclose the enclosing paragraph. It's common practice to spoil in a paragraph or even within a sentence.
  • Chrome (correctly) opens details if find-in-page matches, which is something that you do not want to happen with spoilers.
  • The element (currently) cannot be styled in a way that matches user expectations.

Previously

gregwhitworth commented 1 year ago

This is an interesting issue for sure. I'm not entirely sure if Open UI is the right place or if this should go directly to WHATWG. However, you're correct that this usecase is common and will have accessibility implications irrespective of which venue decides to pick it up. One thing that I'd benefit from understanding is if you have usecases that you can share that have broken accessibility. At any rate, it's worth raising this to the group to see if there is interest in producing an explainer. @jimmyfrasche any interest in helping draft it?

jimmyfrasche commented 1 year ago

@gregwhitworth I'm not sure how much help I can provide, but I'm happy to help in any way I can.

One thing that I'd benefit from understanding is if you have usecases that you can share that have broken accessibility.

While there are a lot of accessibility issues that I've seen unaddressed in various implementations, the hard one, even if you get everything else right, is that you need a way to re-hide spoilers but the spoiled elements' surface area is the toggle but the spoilered content may itself be interactive. I've seen a lot of urls that were spoiled either to demonstrate that it links to something that is a spoiler or more often simply because the url itself contains a spoiler.

kizu commented 9 months ago

I will copy my message from Open UI discord where I was linked to this issue, as a way to show that there is an interest around this:

Random question: was something like a tag ever proposed as a native HTML element in this group?

Things like ||discord spoilers||, <lj-cut> and many many others were and are prevalent over various platforms like forums, reddits, chats etc.

Not your usual “web app” UI, but UI nevertheless. Basically, an inline disclosure widget, probably? <details> cannot be used inside paragraphs or any inline context, so should we have something that could be used this way?

(ok, the question is not entirely random, but came from me experimenting with declarative shadow DOM landing in Firefox Nightly — https://codepen.io/kizu/pen/vYbqzRY)

Some more notes:

I want to note that the “black bars” display is not the only way this might be used, and there are cases for inline summary-like spoilers, where you'd want to have some text.

Then, I'm not entirely sure if “toggleable” spoilers is the only way it should be implemented, and if the one-way only spoilers are an ok pattern.

By having a native element, we could at least ensure keyboard navigation for showing it, as currently many implementations in the wild are not keyboard-accessible (see Discord, unless there is some hidden option that makes them such).

I can also see people wanting the absence of an ability to collapse the spoiler. There might be many reasons people could want this: to reflect the “spoilery” nature of it, where you might be unable to “unsee” it, or to reflect the “scratch window” pattern, where once you “open” it, you cannot go back.

I still think the default should be toggleable both ways, but with a way to make it a one-way deal / provide styling hooks which will allow to do it.

The challenging part: how should the two-way toggling be implemented by default? Adding an extra element like the summary's marker? Something else? I will vote against making the whole area clickable, unless it would be easy to select the text inside regardless — as you might often want to copy the content of such spoilers as text.

jimmyfrasche commented 9 months ago

I've seen one-shot spoilers before but I was always chalked it up to a bad implementation. I've unspoilered then immediately respoilered many a time and wouldn't want to lose that. Is there a use case where you absolutely must not be able to respoiler? If it's just a preference I'd prefer for user need to override developer want here.

brennanyoung commented 7 months ago

Just an observation: "unspoiler"/"respoiler" are confusing coinage, it's not clear which of these refers to the concealed state.

Biggest a11y issue with home-grown spoiler mechanisms is that assistive tech can often access the concealed content.

Note also that nesting operable elements inside operable elements creates accessibility issues; the toggled content may very well contain hyperlinks, controls and whatnot, so making the whole area clickable is not a good idea.

One more point: If details/summary could be made to work inline, and also could be permitted to be styled in "closed" state, then the problem is essentially solved.

brennanyoung commented 7 months ago

I provide another use case for facilitating re-hiding: NSFW content.

Something NSFW has been revealed (accidentally, of course) and you don't want to leave it on the screen where the boss/spouse/parent/kids might glimpse it.

jimmyfrasche commented 7 months ago

The only thought I've had for how to expose the toggle is a tab on top of the linebox that only shows when the spoiler element itself matches :hover or :focus.

I've not seen such in the wild but it's the only thing I can think of that maintains the property of not getting in the way of the now unhidden content. Even something simple like a (+)/(-) at the front breaks the flow up:

Consider: I think the murderer is [spoilered text] / I think the murderer is the butler

vs: I think the murderer is (+)[spoilered text] / I think the murderer is (-)the butler

Having a button in the middle of a sentence breaks up the flow. I'm worried that it would inhibit adoption if it's perceived as "more annoying" than the easier, less accessible versions.

To use details/summary for this these things are necessary:

There's a site I go to that runs some ancient hypermodded forums software that replaces [spoiler]some text[/spoiler] with

<span class="spoiler" onmouseover="this.className='spoiler_over'" onmouseout="this.className='spoiler'">some text</span>

with

span.spoiler {
  color: #000;
  background-color: #000;
}

I could probably talk the admins to changing the output to <spoiler>some text</spoiler> once it had decent cross browser support. I don't think I could talk them into replacing it with a lot more code that could cause maintenance issues in the future.

jimmyfrasche commented 7 months ago

Here's a rough sketch of how I think this should work ideally. All names below are placeholders to be decided later but I needed something for the sake of concreteness.

<spoiler open><summary>book spoiler</summary>the secret text</spoiler>

The spoiler tag is an interactive inline element with role=spoiler. The summary tag is optional and can be used to provide additional context about why the content is hidden and is used to set the ariaLabel of the spoiler.

The open attribute is set when the spoiled text is revealed. (The UA may choose to persist this state across page reloads.)

At all times there is redaction layer above the contents (extending beyond the bounding box of the tag if any child content pokes out). The default styling is to set the background-color property of this layer to transparent when open and to a solid color otherwise. Regardless of how this is styled, a spoiler that is not open marks its content inert.

The spoiler tag is a tab stop and can be toggled with a click event. In <a href=#>A</a><spoiler open><a href=#>B</a></spoiler><a href=#>C</a> the tab stops are A, spoiler, B, C. When closed they are A, spoiler, C.

If there is a summary this is shown in a popover anchored to the spoiler when the spoiler is focused or in a :hover state. If there is no summary the popover is still shown when open, with some fallback text. Clicking the popover removes the open attribute.

The default style should include a slight box-shadow regardless of state to make it clear where it starts and ends.

There must be pseudoelements for styling the redaction layer and popover.

The only novel addition there is the popover to solve the issues with closing an open spoiler. Everything else is paved cow path.

github-actions[bot] commented 1 month ago

There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.

DrewBrasher commented 3 weeks ago

I think this would be a great standard to have! I agree with some of the other comments that being able to re-hide the content would be an important feature.

brennanyoung commented 3 weeks ago

Having a button in the middle of a sentence breaks up the flow. I'm worried that it would inhibit adoption if it's perceived as "more annoying" than the easier, less accessible versions.

@jimmyfrasche Thank you for making this crucial observation!

I just want to add that the main functional difference between a button and a hyperlink is that a hyperlink does not respond to a SPACE keypress (as a button would do). Instead, pressing SPACE scrolls the document (default behavior for browsing flow content).

Assistive tech handles inline hyperlinks in such a way that they make only a minimal interruption of the reading flow. This is (I think) what you are calling for.

So, if one of the requirements is that this 'spoiler' element be part of the flow, then it should be modelled on <a> rather than <button>.

Or to put it another way "Spoilers" (or NSFW content) are, or should be (semantically speaking) kinds of hypertext, rather than form elements.

jimmyfrasche commented 3 weeks ago

To clarify I mean that visually adding a button would be bad. Aurally, there's going to be something there regardless as the screen reader needs to inject its announcements into the text, that's just how it works.

DavidJCobb commented 5 days ago

While there are a lot of accessibility issues that I've seen unaddressed in various implementations, the hard one, even if you get everything else right, is that you need a way to re-hide spoilers but the spoiled elements' surface area is the toggle but the spoilered content may itself be interactive. I've seen a lot of urls that were spoiled either to demonstrate that it links to something that is a spoiler or more often simply because the url itself contains a spoiler.

Maybe this is something that'd have to come down to usage and accessibility guidelines -- in much the same way that it's a guideline not to write things like "Click here to reticulate the splines," rather than hyperlinks as a feature being designed in a way that makes unhelpful link text impossible.

The only thought I've had for how to expose the toggle is a tab on top of the linebox that only shows when the spoiler element itself matches :hover or :focus. I've not seen such in the wild but it's the only thing I can think of that maintains the property of not getting in the way of the now unhidden content.

A potential problem with a tab hovering above the revealed-spoiler line box is that it could cover up the line box above the spoiler. TVTropes, for example, often has articles filled with hidden spoilers -- many of them being a paragraph long, and some being adjacent to one another. If you've already read/seen/played a work being covered on TVTropes, you'll probably want to reveal spoilers several at a time as you read that work's article, in which case you'll have little hovering tabs all over the place, sometimes even covering up other revealed spoilers. (The site has an option to reveal spoilers in bulk, but that option persists across pages, which is generally undesirable.)

Here's an example from their article on Detroit: Become Human, where multiple long spoilers are listed one after another. If one were to reveal all of these spoilers at once, and the way to reconceal a spoiler was to click on a newly-appeared hovering button, then buttons from each spoiler would partially cover the previous spoiler, impairing readability.

image

jimmyfrasche commented 4 days ago

@DavidJCobb

An a in a spoiler is an easily surmountable problem that I've included only as a demonstration of how poorly these things can be implemented in practice. Having a browser provided part that covers the spoiled contents solves that entirely.

The idea for the pop out button is that it only pops out when you're interacting with a single spoiler to remain as unobtrusive as possible. When doing so it would cover the previous linebox but only one at a time. Not a lot of help on mobile so it cannot be the sole affordance but it would still be an improvement on the status quo.