Using & Styling The Details Element

Using & Styling The Details Element

You could find the <particulars> factor everywhere in the internet today. We have been excited about it when it first dropped and toyed with using it as a menu again in 2019 (however probably don’t) amongst many other experiments. John Rhea made a whole recreation that combines <details> with the Popover API!

Now that we’re 5+ years into <particulars>, we all know extra about it than ever earlier than. I believed I’d spherical that data up so it’s in a single place I can reference sooner or later with out having to go looking the location — and different websites — to search out it.

The essential markup

It’s a single factor:

<particulars>
  Open and shut the factor to toggle this content material.
</particulars>

That “particulars” label is a default. We will insert a <abstract> factor to give you one thing customized:

<particulars>
  <abstract>Toggle content material</abstract>
  Open and shut the factor to toggle this content material.
</particulars>

From right here, the world is sorta our oyster as a result of we are able to stuff any HTML we would like contained in the factor:

<particulars>
  <abstract>Toggle content material</abstract>
  <p>Open and shut the factor to toggle this content material.</p>
  <img src="https://css-tricks.com/using-styling-the-details-element/path/to/picture.svg" alt="">
</particulars>

The content material is (sorta) searchable

The difficulty with tucking content material inside a component like that is that it’s hidden by default. Early on, this was thought-about an inaccessible follow as a result of the content material was undetected by in-page looking out (like utilizing CMD+F on the web page), however that’s since modified, at the very least in Chrome, which can open the <particulars> factor and reveal the content material if it discovers a matched time period.

That’s sadly not the case in Firefox and Safari, each of which skip the content material stuffed inside a closed <particulars> factor when doing in-page searches on the time I’m penning this. However it’s much more nuanced than that as a result of Firefox (testing 134.0.1) matches searches when the <particulars> factor is open, whereas Safari (testing 18.1) skips it altogether. That might very nicely change by the tip of this 12 months since searchability is one of the items being tackled in Interop 2025.

So, as for now, it’s a good suggestion to maintain essential content material out of a <particulars> factor when attainable. For instance, <particulars> is usually used as a sample for Continuously Requested Questions, the place every “query” is an expandable “reply” that reveals extra data. That may not be the most effective thought if that content material needs to be searchable on the web page, at the very least for now.

Open one by one

All now we have to do is give every <particulars> an identical identify attribute:

<particulars identify="notes">
  <abstract>Open Be aware</abstract>
  <p> ... </p>
</particulars>
<particulars identify="notes"> <!-- and many others. --> </particulars>
<particulars identify="notes"> <!-- and many others. --> </particulars>
<particulars identify="notes"> <!-- and many others. --> </particulars>

This enables the weather to behave much more like true accordions, the place one panel collapses when one other expands.

Type the marker

The marker is that little triangle that signifies whether or not the <particulars> factor is open or closed. We will use the ::marker pseudo-element to type it, although it does include constraints, specifically that each one we are able to do is change the colour and font dimension, at the very least in Chrome and Firefox which each absolutely help ::marker. Safari partially helps it within the sense that it really works for ordered and unordered checklist gadgets (e.g., li::marker), however not for <particulars> (e.g., abstract::marker).

Let’s take a look at an instance that kinds the markers for each <particulars> and an unordered checklist. On the time I’m penning this, Chrome and Firefox help styling the ::marker in each locations, however Safari solely works with the unordered checklist.

Discover how the ::marker selector in that final instance selects each the <particulars> factor and the unordered checklist factor. We have to scope the selector to the <particulars> factor if we wish to goal simply that marker, proper?

/* This does not work! */
particulars::marker { 
  /* kinds */
}

Nope! As a substitute, we have to scope it to the <abstract> factor. That’s what the marker is definitely connected to.

/* This does work */
abstract::marker { 
  /* kinds */
}

You would possibly suppose that we are able to type the marker even when we have been to go away the abstract out of the markup. In spite of everything, HTML routinely inserts one for us by default. However that’s not the case. The <abstract> factor must be current within the markup for it to match kinds. You’ll see within the following demo that I’m utilizing a generic ::marker selector that ought to match each <particulars> components, however solely the second matches as a result of it accommodates a <abstract> within the HTML. Once more, solely Chrome and Firefox help in the intervening time:

You may additionally suppose that we are able to swap out the triangle for one thing else since that’s one thing we are able to completely do with checklist gadgets by the use of the list-style-type property:

/* Doesn't work! */
abstract::marker {
  list-style-type: sq.;
}

…however alas, that’s not the case. An article over at internet.dev says that it does work, however I’ve been unsuccessful at getting a correct instance to work in any browser.

That isn’t to say it shouldn’t work that manner, however the specification isn’t explicit about it, so I’ve no expectations a technique or one other. Maybe we’ll see an edit in a future specification that will get particular with <particulars> and to what extent CSS can modify the marker. Or possibly we received’t. It might be good to have some approach to chuck the triangle in favor of one thing else.

And what about eradicating the marker altogether? All we have to do is about the content material property on it with an empty string worth and voilà!

As soon as the marker is gone, you may determine to craft your personal customized marker with CSS by hooking into the <abstract> factor’s ::earlier than pseudo-element.

Simply take be aware that Safari shows each the default marker and the customized one because it doesn’t help the ::marker pseudo-element on the time I’m penning this. You’re most likely as drained studying that as I’m typing it. 🤓

Type the content material

Let’s say all you could do is slap a background shade on the content material contained in the <particulars> factor. You would choose all the factor and set a background on it:

particulars {
  background: oklch(95% 0.1812 38.35);
}

That’s cool, however it could be higher if it solely set the background shade when the factor is in an open state. We will use an attribute selector for that:

particulars[open] {
  background: oklch(95% 0.1812 38.35);
}

OK, however what concerning the <abstract> factor? What if you happen to don’t need that included within the background? Nicely, you may wrap the content material in a <div> and choose that as an alternative:

particulars[open] div {
  background: oklch(95% 0.1812 38.35);
}

What’s even higher is utilizing the ::details-content pseudo-element as a selector. This manner, we are able to choose the whole lot contained in the <particulars> factor with out reaching for extra markup:

::details-content {
  background: oklch(95% 0.1812 38.35);
}

There’s no want to incorporate particulars within the selector since ::details-content is simply ever selectable within the context of a <particulars> factor. So, it’s like we’re implicitly writing particulars::details-content.

The ::details-content pseudo remains to be gaining browser help once I’m penning this, so it’s value maintaining a tally of it and utilizing it cautiously within the meantime.

Animate the opening and shutting

Click on a default <particulars> factor and it instantly snaps open and closed. I’m not against that, however there are occasions when it would look (and really feel) good to transition like a easy operator between the open and closed states. It used to take some intelligent hackery to drag this off, as Louis Hoebregts demonstrated using the Web Animations API several years back. Robin Rendle shared one other manner that makes use of a CSS animation:

particulars[open] p {
  animation: animateDown 0.2s linear forwards;
}

@keyframes animateDown {
  0% {
    opacity: 0;
    remodel: translatey(-15px);
  }
  100% {
    opacity: 1;
    remodel: translatey(0);
  }
}

He sprinkled in just a little JavaScript to make his last instance absolutely interactive, however you get the concept:

Discover what’s taking place in there. Robin selects the paragraph factor contained in the <particulars> factor when it’s in an open state then triggers the animation. And that animation makes use of intelligent positioning to make it occur. That’s as a result of there’s no approach to know precisely how tall the paragraph — or the dad or mum <particulars> factor — is when expanded. Now we have to make use of specific sizing, padding, and positioning to drag all of it collectively.

However guess what? Since then, we bought a massive present from CSS that enables us to animate an element from zero height to its auto (i.e., intrinsic) height, even when we don’t know the precise worth of that auto top prematurely. We begin with zero top and clip the overflow so nothing hangs out. And since now we have the ::details-content pseudo, we are able to instantly choose that moderately than introducing extra markup to the HTML.

::details-content {
  transition: top 0.5s ease, content-visibility 0.5s ease allow-discrete;
  top: 0;
  overflow: clip;
}

Now we are able to choose into auto-height transitions utilizing the interpolate-size property which was created simply to allow transitions to key phrase values, similar to auto. We set it on the :root factor in order that it’s accessible in all places, although you may scope it on to a extra particular occasion if you happen to’d like.

:root {
  interpolate-size: allow-keywords;
}

Subsequent up, we choose the <particulars> factor in its open state and set the ::details-content top to auto:

[open]::details-content {
  top: auto;
}

We will make it in order that this solely applies if the browser helps auto-height transitions:

@helps (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  [open]::details-content {
    top: auto;
  }
}

And at last, we set the transition on the ::details-content pseudo to activate it:

::details-content {
  transition: top 0.5s ease;
  top: 0;
  overflow: clip;
}

/* Browser helps interpolate-size */
@helps (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  [open]::details-content {
    top: auto;
  }
}

However wait! Discover how the animation works when opening <particulars>, however issues snap again when closing it. Bramus notes that we have to embrace the content-visibility property within the transition as a result of (1) it’s implicitly set on the factor and (2) it maps to a hidden state when the <particulars> factor is closed. That’s what causes the content material to snap to hidden when closing the <particulars>. So, let’s add content-visibility to our checklist of transitions:

::details-content {
  transition: top 0.5s ease, content-visibility 0.5s ease allow-discrete;
  top: 0;
  overflow: clip;
}

/* Browser helps interpolate-size */
@helps (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  [open]::details-content {
    top: auto;
  }
}

That’s significantly better:

Be aware the allow-discrete key phrase which we have to set since content-visibility is a property that solely helps discrete animations and transitions.

Fascinating tips

Chris has a demo that makes use of <particulars> as a system for floating footnotes in content material. I forked it and added the identify attribute to every footnote in order that they shut when one other one is opened.

I discussed John Rhea’s “Pop(over) The Balloons” game on the high of those notes:

Bramus with a slick-looking horizontal accordion forked from one other instance. Be aware how the <particulars> factor is used as a flex container:

Chris with another clever trick that makes use of <particulars> to play and pause animated GIF picture information. It’s doesn’t truly “pause” however the impact makes it look like it does.

Ryan Trimble with styling <particulars> as a dropdown menu after which utilizing anchor positioning to set the place the content material opens.

References

Leave a Reply