DEV Community

Cover image for Spoiler/sensitive element in HTML and CSS
Alvaro Montoro
Alvaro Montoro

Posted on • Originally published at alvaromontoro.com

Spoiler/sensitive element in HTML and CSS

Sometimes we need to hide parts of the page from the users. It may be a spoiler or sensitive content and pictures that we want users to approve before displaying them.

There are a couple of HTML elements that will natively do what we want: <details> and <summary>. They have native collapsed/expanded states that the browser handles to show/hide the information, so we don't need any JavaScript.

See them in action here:

They work fine, but the default style looks bland and simple. Also, the content shifts up and down when we expand and collapse the details, which is a bit annoying.

Instead of hiding the content, we could try displaying it blurred when the details are collapsed and normal when the details are open. Unfortunately, at the moment, there is no way to show the content when the details are collapsed.

With a bit of ingenuity, we can simulate that behavior... and it will only require a handful of lines of CSS code!

We want to show the content, but we cannot. Instead, we can show a pseudo-element like ::after with the exact content of the <details>.

A CSS variable will have a value with the content of <details> (without the <summary>). Which will require a small change in the HTML:

<details class="spoiler" style="--hidden: 'Text to be hidden'">
  ...
</details>
Enter fullscreen mode Exit fullscreen mode

Why a variable and not a data attribute? Because data attributes are interpreted as text. They worked fine with text content, but they didn't play nice when we wanted to hide an image.

Then on CSS, we will read that variable and put it in the ::after pseudo-element, applying a filter on close, and hiding when the <details> is expanded:

details.spoiler::after {
  content: var(--hidden);
  filter: blur(4px);
}

details[open]::after {
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

This makes our new spoiler section look like this:

It looks a lot better... but it has a big problem: it doesn't work on Firefox! While Chrome and Safari show the ::after of the <details>, Firefox doesn't because it considers that it is inside the collapsed <details> (which, to be honest, should be the expected behavior anyway.)

To go around it, we can change the CSS a little, so instead of using the ::after of the <details>, we use the ::after of the <summary>.

details.spoiler summary::after {
  content: var(--hidden);
  filter: blur(4px);
  display: block;
}

details[open] summary::after {
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

The result is on this Codepen:

Now this works in all major browsers (Chrome, Firefox, and Safari) and, as we are using the ::after in the <summary>, it has the added feature that it will show the hidden content when we click on the actual blurred content (before it was only on the warning area.)


This is a way to create a spoiler section that would be great for hiding sensitive content or spoilers. And it only uses standard HTML and 8 lines of CSS! The browser handles all the logic for showing/hiding without needing any JavaScript.

Some good things about this solution:

  • Little code: it's literally adding an attribute in HTML and 8 lines of CSS.
  • Standard HTML: it is supported by all major browsers (basically, everything but IE and old versions of Edge.)
  • Content can be rehidden: if we want to hide the content, we can click again on the <summary>.

...and some not-so-good things about it:

  • Works better with little content: this solution is for single paragraphs or images. It would be tricky to hide large chunks of text.
  • May require additional styling: we will need to update the CSS for the ::after to match the style of the content inside the <details> so there's no "jump effect" on show/hide.

Top comments (4)

Collapse
 
afif profile image
Temani Afif

I would go with a label/input configuration like this: codepen.io/t_afif/pen/dyNwNyQ where you don't need to duplicate the content.

Collapse
 
alvaromontoro profile image
Alvaro Montoro

That is a great idea, and not having to duplicate the content is a big plus.

Collapse
 
natalia_asteria profile image
Natalia Asteria

Honestly the third codepen needs more blur there. Any kind of NSFW content would be easily seen. And obviously, some people will accidentally click on the details tag.

Collapse
 
sergeyie profile image
Sergey Ieffe

This gonna work great with frequently asked questions sections.