Spoiler/sensitive element in HTML and CSS
Tags: html, css, webdev, tutorial
Published: 2021-04-22 15:00:18

---
title: Spoiler/sensitive element in HTML and CSS
published: true
description: 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.  In this post, we are going to see how to create such a section using only standard HTML and CSS and letting the browser handle the logic.
tags: html,css,webdev,tutorial
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m7c4fuoshq6ryudeoio9.png
canonical_url: https://alvaromontoro.com/blog/67975/spoiler-sensitive-sections-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>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) and [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/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](https://codepen.io/alvaromontoro/full/GRrwdvM):

{% codepen https://codepen.io/alvaromontoro/pen/GRrwdvM %}

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`](https://developer.mozilla.org/en-US/docs/Web/CSS/::after) with the exact content of the `<details>`\.

A [CSS variable](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) will have a value with the content of `<details>` (without the `<summary>`). Which will require a small change in the HTML:


```html
<details class="spoiler" style="--hidden: 'Text to be hidden'">
  ...
</details>
```

> Why a variable and not a [data attribute](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes)? 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](https://developer.mozilla.org/en-US/docs/Web/CSS/filter) on close, and hiding when the `<details>` is expanded:

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

details[open]::after {
  display: none;
}
```

This makes our [new spoiler section look like this](https://codepen.io/alvaromontoro/full/bGgQyoX):

{% codepen https://codepen.io/alvaromontoro/pen/bGgQyoX %}

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>`. 

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

details[open] summary::after {
  display: none;
}
```

The result is [on this Codepen](https://codepen.io/alvaromontoro/full/MWJzJBB):

{% codepen https://codepen.io/alvaromontoro/pen/MWJzJBB %}

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.