Yow will discover the <particulars>
component all around the internet as of late. We had been enthusiastic about it when it first dropped and toyed with utilizing it as a menu again in 2019 (however in all probability don’t) amongst many different experiments. John Rhea made a complete sport that combines <particulars>
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 info up so it’s in a single place I can reference sooner or later with out having to go looking the positioning — and different websites — to search out it.
The fundamental markup
It’s a single component:
<particulars>
Open and shut the component to toggle this content material.
</particulars>
That “particulars” label is a default. We are able to insert a <abstract>
component to provide you with one thing customized:
<particulars>
<abstract>Toggle content material</abstract>
Open and shut the component to toggle this content material.
</particulars>
From right here, the world is sorta our oyster as a result of we will stuff any HTML we would like contained in the component:
<particulars>
<abstract>Toggle content material</abstract>
<p>Open and shut the component 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 apply as a result of the content material was undetected by in-page looking (like utilizing CMD
+F
on the web page), however that’s since modified, at the very least in Chrome, which can open the <particulars>
component 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>
component when doing in-page searches on the time I’m scripting this. But it surely’s much more nuanced than that as a result of Firefox (testing 134.0.1) matches searches when the <particulars>
component is open, whereas Safari (testing 18.1) skips it altogether. That would very properly change by the top of this yr since searchability is without doubt one of the objects being tackled in Interop 2025.
So, as for now, it’s a good suggestion to maintain necessary content material out of a <particulars>
component when doable. For instance, <particulars>
is commonly used as a sample for Often Requested Questions, the place every “query” is an expandable “reply” that reveals extra info. That may not be the perfect concept if that content material ought to be searchable on the web page, at the very least for now.
Open separately
All we now 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 permits the weather to behave much more like true accordions, the place one panel collapses when one other expands.
Model the marker
The marker is that little triangle that signifies whether or not the <particulars>
component is open or closed. We are able to use the ::marker
pseudo-element to model it, although it does include constraints, particularly that each one we will do is change the colour and font measurement, 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 listing objects (e.g., li::marker
), however not for <particulars>
(e.g., abstract::marker
).
Let’s have a look at an instance that types the markers for each <particulars>
and an unordered listing. On the time I’m scripting this, Chrome and Firefox help styling the ::marker
in each locations, however Safari solely works with the unordered listing.
Discover how the ::marker
selector in that final instance selects each the <particulars>
component and the unordered listing component. We have to scope the selector to the <particulars>
component if we wish to goal simply that marker, proper?
/* This does not work! */
particulars::marker {
/* types */
}
Nope! As an alternative, we have to scope it to the <abstract>
component. That’s what the marker is definitely hooked up to.
/* This does work */
abstract::marker {
/* types */
}
You would possibly assume that we will model the marker even when we had been to go away the abstract out of the markup. In any case, HTML mechanically inserts one for us by default. However that’s not the case. The <abstract>
component needs to be current within the markup for it to match types. You’ll see within the following demo that I’m utilizing a generic ::marker
selector that ought to match each <particulars>
parts, however solely the second matches as a result of it comprises a <abstract>
within the HTML. Once more, solely Chrome and Firefox help in the intervening time:
You may also assume that we will swap out the triangle for one thing else since that’s one thing we will completely do with listing objects 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 specific about it, so I’ve no expectations a method 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 will be good to have some strategy to chuck the triangle in favor of one thing else.
And what about eradicating the marker altogether? All we have to do is ready the content material
property on it with an empty string worth and voilà!
As soon as the marker is gone, you would determine to craft your individual customized marker with CSS by hooking into the <abstract>
component’s ::earlier than
pseudo-element.
Simply take notice 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 scripting this. You’re in all probability as drained studying that as I’m typing it.
Model the content material
Let’s say all it’s essential do is slap a background coloration on the content material contained in the <particulars>
component. 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 coloration when the component is in an open
state. We are able to use an attribute selector for that:
particulars[open] {
background: oklch(95% 0.1812 38.35);
}
OK, however what in regards to the <abstract>
component? What should you don’t need that included within the background? Effectively, you would wrap the content material in a <div>
and choose that as a substitute:
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 fashion, we will choose all the things contained in the <particulars>
component 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>
component. So, it’s like we’re implicitly writing particulars::details-content
.
The ::details-content
pseudo continues to be gaining browser help after I’m scripting this, so it’s price keeping track of it and utilizing it cautiously within the meantime.
Animate the opening and shutting
Click on a default <particulars>
component and it instantly snaps open and closed. I’m not against that, however there are occasions when it’d 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 tug this off, as Louis Hoebregts demonstrated utilizing the Internet Animations API a number of years again. 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 somewhat JavaScript to make his closing instance absolutely interactive, however you get the concept:
Discover what’s taking place in there. Robin selects the paragraph component contained in the <particulars>
component 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 strategy to know precisely how tall the paragraph — or the dad or mum <particulars>
component — is when expanded. We have now to make use of specific sizing, padding, and positioning to tug all of it collectively.
However guess what? Since then, we acquired a large present from CSS that enables us to animate a component from zero peak to its auto (i.e., intrinsic) peak, even when we don’t know the precise worth of that auto peak upfront. We begin with zero peak and clip the overflow so nothing hangs out. And since we now have the ::details-content
pseudo, we will instantly choose that quite than introducing extra markup to the HTML.
::details-content {
transition: peak 0.5s ease, content-visibility 0.5s ease allow-discrete;
peak: 0;
overflow: clip;
}
Now we will 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
component in order that it’s accessible all over the place, although you would scope it on to a extra particular occasion should you’d like.
:root {
interpolate-size: allow-keywords;
}
Subsequent up, we choose the <particulars>
component in its open
state and set the ::details-content
peak to auto
:
[open]::details-content {
peak: auto;
}
We are able to 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 {
peak: auto;
}
}
And at last, we set the transition on the ::details-content
pseudo to activate it:
::details-content {
transition: peak 0.5s ease;
peak: 0;
overflow: clip;
}
/* Browser helps interpolate-size */
@helps (interpolate-size: allow-keywords) {
:root {
interpolate-size: allow-keywords;
}
[open]::details-content {
peak: 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 component and (2) it maps to a hidden state when the <particulars>
component 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 listing of transitions:
::details-content {
transition: peak 0.5s ease, content-visibility 0.5s ease allow-discrete;
peak: 0;
overflow: clip;
}
/* Browser helps interpolate-size */
@helps (interpolate-size: allow-keywords) {
:root {
interpolate-size: allow-keywords;
}
[open]::details-content {
peak: auto;
}
}
That’s a lot 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” sport on the prime of those notes:
Bramus with a slick-looking horizontal accordion forked from one other instance. Be aware how the <particulars>
component is used as a flex container:
Chris with one other intelligent trick that makes use of <particulars>
to play and pause animated GIF picture information. It’s doesn’t really “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.