Known gaps

What is missing, thin or unfinished in what exists today. The argument about whether to adopt at all is on should you switch?.

Ordered by how likely each one is to bite.

Missing behaviour

Each of these is a thing Radix does that bedrock does not. None is a bug; each is a decision, and the reason is in the last column.

Gap What you lose Why
No scroll lock With a modal dialog open, the page behind it still scrolls on wheel. showModal() makes the background inert to interaction, not to scrolling. react-remove-scroll is part of the 13.7 kB you deleted. html:has(dialog:modal) { overflow: hidden } gets it back, and scrollbar-gutter: stable on the root pays for the layout shift with nothing measured; these docs do exactly that, in styles/site.css. The root is the only scroller that needs it: the backdrop hit-tests to the <dialog>, and a modal dialog is position: fixed, so the scroll chain is the viewport, never a scroller the dialog happens to sit inside and never one the pointer is over. It stays yours rather than ours because whether the page behind freezes is a decision about your layout, not about the dialog.
Slider takes one value No two-thumb range. A range input has one thumb. Two thumbs is two inputs sharing a track: a different component, not a prop.
An anchored panel lags a fast scroll Scroll a page with a tooltip, hover card or popover open on a phone and the panel trails the trigger by a frame or two before catching up. Not ours to fix, and not a reason to go back to JavaScript. Scrolling runs on the compositor thread; anchor positioning is resolved in layout, on the main thread. The panel is therefore repositioned a frame behind a scroll the compositor is already drawing. A JavaScript positioner is strictly worse — it needs a scroll listener, a measure and a write, all on the same main thread, one frame later still. The fix is position-anchor being handled on the compositor, which is Chromium's to ship. Until then, closing the panel on scroll is a reasonable thing for an app to do; it is not something the library will do to you.
Toast has no swipe-to-dismiss Pointer-gesture dismissal. No native equivalent. Left out rather than half-implemented.
Accordion cannot refuse to close Radix's collapsible={false}, where the open item stays open until another is chosen. type="single" is <details name>, and a <summary> toggles. No native equivalent.
A controlled <details> cannot refuse Under /controlled, Collapsible and Accordion report a toggle they cannot decline. Returning early from onOpenChange leaves the disclosure where the user put it, with open (or value) disagreeing until something else changes it. <details> fires no beforetoggle and no cancel, only a toggle after the fact, so there is no decision to take part in. Reverting afterwards was the stated intent for a while and three comments promised it; it was never delivered, and it is not worth delivering: it would be a visible flicker, and toggle is dispatched asynchronously, so an accept that has not re-rendered yet is indistinguishable from a refusal. The veto that does work is preventDefault() on the trigger's click, which controlled state shows.
No missing-Title warning Radix's development warning that a dialog has no accessible name. aria-labelledby is only written when a Title is rendered, so the reference can no longer dangle, but nothing tells you the name is absent.
id on Dialog.Content is not forwarded Passing one is silently ignored. The trigger's commandfor points at it. The one exception to "every part forwards id".

Wrong or overstated

Where The problem
validate-trigger.ts Its message says a non-button trigger costs you "implicit aria-expanded". Measured: a popover invoker gets that from the platform, a dialog invoker does not, because Dialog.Trigger writes it by hand. Right for Popover and Tooltip, wrong for the primitive most people hit it on.

Thin coverage

The tests are real and they run against a real browser. What they do not do is cover evenly.

Area State
Dialog Radix's own suite ported, plus 20 specs. The deepest by a distance.
Most primitives Between one and seven specs: enough to catch the design being wrong, not every regression.
Menubar, NavigationMenu, ContextMenu The thinnest.
Appearance Nothing. Playwright asserts behaviour, never how it looks, so the transition sequencing bedrock.css demonstrates, the thing most likely to regress silently, has no test at all.
Bundle size The per-primitive figures are measured by hand, not asserted in CI.
Other engines The suite runs Chrome. A cross-browser matrix today would report failures that are the documented state of the world rather than regressions. That is a defensible reason not to have one, and not a reason to trust the other engines.

The registry is incomplete and unproven

24 items cover everything that was Radix-backed except menubar, navigation-menu, toast, sheet and drawer.

Five of them now render on the registry page from the shipped files, which catches a wrong class name or a missing export in those five. The other nineteen have never been installed into a real shadcn app and looked at, and nothing renders any of them in a Next.js project the way a consumer would.

Documentation

Every primitive has a reference page and a running demo, and every demo is asserted to mount and to work. What is left: