<details>
stylingL. David Baron, dbaron@chromium.org, April-May 2023
The HTML details
element represents a
disclosure widget.
It can also be used as a part of an
accordion widget.
However, there are many disclosure widgets on the web
that do not use the details
element.
In many cases, the styling of these disclosure widgets
is not achievable using the details
element.
We should instead be in a situation where stylability
is not an obstacle to the use of the details
element
for the vast majority of disclosure widgets on the Web.
Developers regularly use disclosure and accordion widgets on the Web. Today, that often means that they build their own widget rather than using a widget provided by the platform.
This proposal is suggesting that we add features that would enable developers to use the platform’s widget in more cases (hopefully the vast majority of cases). Doing so would help users because it would make (or at least would enable making) the user experience more consistent, and generally better, in a number of areas:
Reducing the need for developers to build their own widgets should also reduce the size of pages that use such widgets, which reduces the time and bandwidth needed for users to load those pages.
Implementations in Chromium, Gecko, and WebKit all use Shadow DOM
to implement the details
element. However, it is not possible for
pages to use this to override the behavior of the details
element
because:
Element.attachShadow()
is
not allowed
on the details element.
This appears to be interoperably implemented
(Chromium,
Gecko,
WebKit).<details>
in
all of Chromium, Gecko, and WebKit
is closed (Element.shadowRoot
is null
)
(see test).In all three implementations,
it is possible to completely remove the disclosure triangle
as long as there is a summary
element.
However, it currently requires
using display: block
on the summary in Chromium and Gecko
and
using display: none
on a pseudo-element
in WebKit.
Neither technique works for the summary
that is generated when no summary
element is present.
In all three implementations,
attribute selectors (such as with details[open]
)
can be used to change styles based on whether a details
is open
(see test).
Chromium (source) and
Gecko (source)
treat the summary
as a list-item
,
with the following styles:
details > summary:first-of-type {
display: list-item;
counter-increment: list-item 0;
list-style: disclosure-closed inside;
}
details[open] > summary:first-of-type {
list-style-type: disclosure-open;
}
Pages can override these styles (except for the internal default summary, which in both engines has the same styles duplicated in the shadow DOM; Gecko using a linked stylesheet and Chromium using a style attribute).
The details
element uses shadow DOM internally,
containing a slot for the main summary (with a default summary child),
and a slot for the remaining content.
The assignment of the main summary to the slot for the main summary
uses custom C++ code
that calls the
imperative slotting API.
TODO: Check how usable ::marker
is
The details
element uses shadow DOM internally,
containing a style sheet,
a slot for the main summary (with a default summary child),
and a slot for the remaining content.
The assignment of the main summary to the slot for the main summary
uses custom C++ code that handles details specially,
and assigns the main summary to the magic internal-main-summary
slot name.
TODO: Check how usable ::marker
is
WebKit uses the following styles:
summary::-webkit-details-marker {
display: inline-block;
width: 0.66em;
height: 0.66em;
margin-inline-end: 0.4em;
}
The details
element uses shadow DOM internally,
containing a slot for the main summary (with a default summary child),
and a slot for the remaining content.
The assignment of the main summary to the slot for the main summary
uses custom C++ code
that overrides the named slotting mechanism,
slotting the main summary into a slot named summarySlot
.
TODO: Check how usable ::-webkit-details-marker
is
Most disclosure widgets want their own appearance for the open/closed indicator
which by default is a disclosure triangle.
It should be possible to customize its appearance based on open/closed state
and also pseudo-classes like :hover
and :active
.
It should be possible to make arbitrary or nearly-arbitrary layouts of the disclosure triangle (or open/closed indicator), the summary, and the contents of the collapsable area of the widget. For example, it should be possible to position the open/closed indicator in different positions relative to the other parts (such as on the right side), and it should be possible to use these pieces as part of a flex or a grid layout.
It should be possible to have the opening/closing of the details widget animate, and for that animation to be styled with CSS transitions or animations. This includes both animation of the height (with appropriate clipping and maybe opacity) of the contents of the details, and possibly also animation of the marker (e.g., rotation of a marker triangle).
The following are options we have for solving various parts of the above requirements. Many of them do not address the entire problem, so more than one of them is likely to be needed.
Hiding and rebuilding parts of a widget is a common approach for solving widget styling issues on the Web. It is doable today given the default styles for these elements. (Having standard styles across browser engines would slightly reduce the complexity of doing this.)
This has the advantage of being a rather well-worn path,
and also of allowing developers to replace the marker
with whatever they want.
It has the disadvantage that
any keyboard behavior, focus behavior, and ARIA
associated with the default marker is lost.
However, if that behavior is common to the marker and the summary
element
then this less of a problem.
::part()
)We could have pseudo-elements to address the three pieces of the disclosure widget: the summary’s container, the open/closed marker, and the container for the collapsable contents. These pseudo-elements could potentially address pieces that have a defined relationship with each other in user-agent shadow DOM content.
The pseudo-elements themselves could be newly-defined CSS pseudo-elements.
However, if this is defined in terms of user-agent shadow DOM,
we also have the option of exposing ::part()
pseudo-elements
from the defined user-agent shadow DOM,
rather than minting new pseudo-elements.
(This hasn’t been done before,
but does seem like something we could reasonably do.
However, it was rejected in
CSS Working Group discussion
and in https://github.com/openui/open-ui/issues/702 .)
The pseudo-element for the open/closed marker should probably be ::marker
,
given the existing use of that pseudo-element,
and that the main summary is currently specified as a list-item
.
Note that if we take this approach, the rules that
are currently specified in HTML as a style
attribute
for the container of the collapsible contents
should be respecified as UA style sheet rules using this pseudo-element,
so that is at the UA sheet level of the cascade
rather than the style attribute level.
::marker
stylingCurrently a
limited set
of properties apply to the ::marker
pseudo-element.
It probably makes sense that many properties like position and float are
not supported on ::marker
(see test).
However, in the context of details
/summary
,
it probably makes more sense than it does for lists
to allow for repositioning of the marker.
(The CSS2.0 marker-offset
property
does not appear to be implemented
in Chromium
or in Gecko
or in WebKit.)
A number of use cases probably could be addressed by supporting
additional properties on ::marker
, such as:
[ This option was rejected during CSS Working Group discussion. ]
Given that major browser engine implementations all
implement details
using user-agent shadow DOM,
it seems like one option for improving stylability of details
would be to allow the replacement of the shadow DOM
so that developers could arrange the relationship of the parts as they need.
This faces the obstacle that of the DOM spec’s restrictions on replacing the shadow DOM of the details element, plus the (new, I think) concept of allowing developers to replace a user-agent provided shadow DOM. These seem like somewhat major obstacles.
On the positive side, it would do a good job of ensuring that developers
can style the details
element as they want.
But developers who replace the shadow DOM
would then be responsible for rebuilding the necessary
key handling, focus behavior, and ARIA integration.
flex
and grid
insides on list-item
sCurrently the
specification
allows only flow
and flow-root
as the inner display types for the
inside of a list-item
; flex
and grid
are not allowed. This means
it is not possible to style the inside of a summary
element as a flex
or grid layout.
This probably isn’t a major problem, but it’s worth noting here that we could adjust this if it were necessary to do so.