Popover
A panel in the top layer, opened by an attribute rather than by a state.
src/components/rahti_ui/popover.rs
Basic
A trigger, a panel, and two attributes doing what Radix needs a portal and a dismiss layer for.
shadcn's own demo. The trigger is a `<button popovertarget="…">` and the panel is a `popover` — that pair is the whole of the open and close, and none of it is JavaScript.
`popovertarget` takes an id, and the trigger and the panel are separate components that cannot see each other — so the pairing is a `name` written on both. It becomes `id="popover-dimensions"` on one and `popovertarget` on the other, and it has to be unique in the document and a valid CSS identifier, because it is also the anchor name.
Opening it moves focus to the `Width` field and closing it puts focus back on the button. That is Radix's FocusScope, and the one line of it the platform does not give away: a `<dialog>` focuses itself, a popover does not.
The caret lands after `100%` rather than in front of it. `focus()` on a text field leaves it at offset 0, so the first keystroke would be typed at the wrong end of the value — Radix avoids that by selecting the field outright, and this puts the caret at the end instead, which is what shadcn's popover looks like when it opens.
Header, title and description
The three parts the registry grew after Radix.
The three parts shadcn added to the registry beside the original four. The header stacks them and sets the text size; the title and the description carry one utility each.
The title is a `<div>` rather than a heading, which is shadcn's own choice — a popover turns up in the middle of a document, and a heading there would land in the outline underneath whatever section it happens to sit in.
Sides
Where the panel opens, said twice.
Radix's `side` and `align`, and they place the panel twice over. Where the browser has CSS anchor positioning it is an inline `position-anchor` and `position-area` and no script runs at all; elsewhere the script measures the anchor and writes `left`/`top`. Both flip when the panel would run off screen.
They are inline styles rather than classes because the anchor name varies per popover, and Tailwind can only emit classes it finds spelled out in the source — the same wall the Tabs hit when a CSS-only tab set turned out to need a rule per tab value.
shadcn's popover defaults to `center` where its dropdown menu defaults to `start`. That difference is kept rather than smoothed over: it is part of what makes the two look like themselves.
Anchor
Something other than the trigger for the panel to open beside.
Radix's Anchor. Give it the popover's `name` and the panel is placed against that element rather than against the button that opened it — so the panel here lines up with the file name on the left, not with the `Details` button on the right.
Both carry the same `anchor-name`, and CSS resolves that to whichever comes last in the document. The script takes the trigger's away at mount, so the answer does not depend on which of the two the page happened to write first.
What the platform does
Most of Radix's Popover, in two attributes.
The top-layer row is not a nicety. A popover opened from inside anything that clips — a Scroll Area, a Sidebar, a cell in a scrolling table — would otherwise be cut off at the edge of it. Radix needs a portal for the same reason.
So the script is left with three jobs: focus, placement in the browsers without anchor positioning, and the two attributes Radix publishes that the platform has no declarative spelling for — `data-state` on the panel and `aria-expanded` on the trigger.
The port
What crossed, and what the popover made unnecessary.
The panel at the top of this page carries `id="popover-dimensions"`. That id is the whole API surface between the two halves, which is why the name has to be unique — and why a component that renders its children twice, as the Sidebar does for its mobile drawer, would otherwise put two panels in one document under one name. The script renames the second at mount.