| Need | Use | Why |
|---|---|---|
| Modal blocking dialog, general content | Dialog | Focus-trapped by default, Title/Description announced |
| Modal requiring explicit confirm/cancel response | AlertDialog | Same anatomy as Dialog, semantically an interrupt |
| Edge-sliding panel needing swipe/snap points | Drawer | Extends Dialog with gestures — plain Dialog if no gesture need |
| Non-modal rich content near a trigger | Popover | Defaults non-modal (modal={false}) |
| Click-triggered action list | Menu | Positions against Trigger |
| Right-click/long-press action list | ContextMenu | Positions at pointer — always pair with a visible control too |
| Persistent File/Edit-style command bar | Menubar | Cross-menu arrow-key switching plain Menus lack |
| Site nav with animated shared-panel dropdowns | NavigationMenu | Shared Viewport for cross-panel transitions |
| Short hint text, keyboard-accessible | Tooltip | Never gate essential info here — touch/AT users can't reach it |
| Rich preview, sighted-mouse-only | PreviewCard | Explicitly excluded from a11y tree — content must be redundant with the link |
| Info-icon hover popup | Popover with openOnHover | Not Tooltip — must stay reachable by touch/AT |
| Stacked/anchored notifications | Toast | Imperative API (add/update/promise), not per-toast JSX |
| Need | Use | Why |
|---|---|---|
| Free-form text with optional suggestions | Autocomplete | Value not constrained to the item set |
| Constrained selection, filterable (large list) | Combobox | Filterable Select |
| Constrained selection, short list, no filter | Select | Keyboard typeahead only |
| Single choice, form-native radio look | Radio + RadioGroup | Mutually exclusive, roving tabindex |
| Boolean, optional indeterminate | Checkbox (+ CheckboxGroup for multi) | Tri-state |
| Boolean, immediate on/off feel | Switch | Two-state only, no indeterminate |
| Numeric input with stepping/scrub | NumberField | Locale-aware formatting, drag-to-scrub |
| Fixed-length code entry (OTP/2FA) | OTPField | Paste-splitting, autoSubmit, autoComplete="one-time-code" |
| Plain text | Input | No formatting/stepping overhead |
| Range/multi-thumb value | Slider | minStepsBetweenValues for min/max pairs |
AlertDialog, not Dialog, when the interaction must interrupt and demand a response — plain Dialog doesn't carry that semantic contract.Drawer, not Dialog, when swipe-to-dismiss or snap points matter — otherwise Drawer's extra anatomy is unjustified.Combobox, not Select, when the item list is long enough to need filtering; use Select for short lists where typeahead suffices.Autocomplete, not Combobox, when free-form text outside the item set must be allowed.Popover (openOnHover), never Tooltip, for "infotip" info-icon content — Tooltip is invisible to touch/AT users.alignItemWithTrigger={false} on Select.Positioner the moment side/align seem to have no effect — the default overlap mode ignores them.Fieldset.Root render={<GroupPrimitive/>} + Fieldset.Legend for any multi-control group (RadioGroup, CheckboxGroup, multi-thumb Slider) — a heading above the group isn't programmatically associated.Slider.Thumb its own aria-label — the single Slider.Label only names the slider as a whole.onValueCommitted, not onValueChange, for expensive side effects on NumberField/Slider — the latter fires continuously during drag/scrub.event.preventBaseUIHandler() inside mergeProps, not eventDetails.cancel(), when intercepting a raw DOM/React event handler; use eventDetails.cancel() when intercepting a Base UI change event (onOpenChange, etc.).Button — style the <a> directly; Button enforces conflicting button semantics.ContextMenu, but ship a visible control for the same action too.Popover.open/checked/value purely to add a CSS class → stop, use the matching data-* attribute instead.Toast, it already handles stacking, swipe-dismiss, and promise-based lifecycle.render-wrapped component "loses" Base UI's click/keyboard behavior → check it spreads props and forwards its ref.opacity is part of the animation (even 0.9999) so getAnimations() detects completion.Field/form-control shared state attributes: data-valid/data-invalid, data-dirty, data-touched, data-filled, data-focused.Form.validationMode default: onSubmit (revalidates invalid fields on change afterward).Dialog/AlertDialog modal default: true. Popover modal default: false.Select.Positioner.alignItemWithTrigger default: true (overrides side/align while active).Accordion.multiple default: false (single-open).mergeProps: prefer over mergePropsN for ≤5 prop sets; className concatenates rightmost-first, event handlers run rightmost-first.useRender.defaultTagName default: 'div' when omitted.