COMPONENT
Caret
The glyph that turns over when the thing beside it opens. It only draws; it never decides.
At rest, and turned
The same glyph at two angles. Nothing here knows what is open β the second one is turned because something set --disclosure-open on it.
<span class="caret" aria-hidden="true">βΎ</span>
<span class="caret" aria-hidden="true" style="--disclosure-open: 1">βΎ</span>Reference
Read from components/caret.css when this page was built, so it cannot fall behind the stylesheet.
.caret--ds-motion-fastNotes
Every disclosure in the system knows it is open differently β a popover by :popover-open, a <details> by its open attribute β and no two of those can be written as one selector. So the owner sets one custom property and this reads it:
.dropdown:has(.dropdown-panel:popover-open) { --disclosure-open: 1 }
.menu-fold[open] { --disclosure-open: 1 }The shared half is the drawing and the transition. The differing half is one selector each, and it stays with the component that owns the state β which is why this is a part rather than the same rotation written out in every disclosure that ever wants one. The signal is a plain 0 or 1 rather than an angle, because .nav-toggle reads the same one to cross-fade its hamburger into a close mark and an angle would be no use to it. One fact, stated once by whoever owns it.
calc(var(--disclosure-open, 0) * 180deg), and never --disclosure-open: 0 declared on .caret itself. A custom property declared on an element beats the same property inherited from an ancestor, so the second spelling would make every owner's open state do nothing at all. That is not hypothetical: .icon-on-cream shipped exactly that way and did nothing whatsoever for as long as it existed.
The state is already announced β a popover invoker reports expanded and a <summary> reports its own β so a caret that announces itself reads the same fact out twice. It is decoration on top of a control that already says what it is doing.