Details component demo
This provides robust animations for <details>
elements while trying to avoid affecting the accessibility or semantics of the elements.
How and why
click
or other UI events, instead acting only on the toggle
event which is the recommended approach as it's triggered whenever anything adds or removes the open
attribute or changes the open
DOM property, be it mouse, keyboard, touch, a screen reader, etc. We also do not change the the open
attribute or property at any point to accomplish the animation, unlike the CSS-Tricks solution.What about a CSS-only solution?
While it is possible to create a CSS-only solution, there are multiple limitations with such an approach:
- There is no way to prevent the content disappearing instantly before the close animation has started without resorting to moving the content outside of the
<details>
because browsers seem to provide no way to force the content to be displayed once the theopen
attribute is removed. - There is currently no CSS-only way to transition from a fixed height to the natural content height; the workaround most solutions use is to animate the
max-height
which is set to a large value when open so that there's a fixed height to transition to; while this does transition open and closed, the open transition doesn't come to smooth stop but usually ends abruptly due to the transition continuing on past the natural content height.
So how does this work?
To implement the requirements above, a JavaScript solution was needed. Animation is done via the Motion One library, which allows for precise start and end heights. That solved part of the problem, but:
- We couldn't rely on the content itself to measure the height of, as it would take up zero height half the time, i.e. when the
open
attribute was present on the<details>
. - Even with an accurate height being always known, the existing content would instantly disappear before the close animation had begun.
The one place in the <details>
that the browser doesn't automagically hide? The <summary>
element. We leave the existing content where it is but clone it to the <summary>
element; care is taken to hide the clone from the accessibility tree and to make it completely uninteractable via the inert
attribute in browsers that support it and falling back to ally.maintain.disabled
in ones that don't. This clone is what we use to always have an up to date and accurate measurement of the content height, and doubles as what you see sliding in and out during the open and close animations. The clone is also kept up to date with the real content so any DOM manipulations after we attach are taken into account.
They can start open
Just add the open
attribute.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
They can be nested
<details>
elements now needed to account for child or descendent <details>
being open; the original implementation relied on setting an inline height and updating that whenever the content size changed, but this turned out to be a nightmare to keep synced and also not lag behind and so have visible content overflow for a few frames. The solution involves only ever having a fixed height during the open and close animations, rebuilding the cloned content before every animation, and the last piece of the puzzle: an animated <details>
will trigger an event when its cloned content is rebuilt, which bubbles up the DOM tree, allowing any parent or ancestor <details>
to rebuild its copy of the cloned content, all without having to know the specifics of its children or descendents.Nest away!
But probably not this much
This is kind of silly
This one is styled but opening and closing is left as the browser default
In other words, this is how it behaves if the JavaScript fails to load or attach: not as smooth, but you can still access the content within.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
This is how it looks with your browser's default styles
Pretty boring, right?
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.