Browse the docs

Primitives

The behavior layer under the richer components: headless, unstyled building blocks in the spirit of Radix UI. A primitive renders no Tailwind classes — it provides state, keyboard handling, ARIA wiring, positioning, and exposes data-state / data-side / data-highlighted attributes for your CSS.

Two ways to install, same source either way:

Copy a file. Every primitive downloads as a single file with the shared core embedded — save it under primitives/ and import it relatively:

curl -o primitives/popover.js https://presetui.com/r/primitives/popover.txt

Copying several? Fetch /r/primitives/core.txt once instead, save it as primitives/core.js, and use each primitive's repo form (which imports ./core.js) from the Source views on this site.

Install a package. Using the full kit? The primitives are already inside @presetui/ui:

import { Popover, PopoverContent, PopoverTrigger } from "@presetui/ui/primitives/popover"

Behavior only — no Tailwind, no styled layer? The standalone package is the same source:

npm install @presetui/primitives
import { Popover, PopoverContent, PopoverTrigger } from "@presetui/primitives/popover"

Both ship subpath exports per primitive and .d.ts types generated from the JSDoc, with a React 19+ peer as the only requirement. Styled components that build on a primitive show a Source · npm tab with their import already pointing at the bundled copy (@presetui/ui/primitives/<name>) — one install, nothing else to add.

The contract

The primitives

PrimitivePartsUsed by
accordionAccordionRoot, AccordionItem, AccordionTrigger, AccordionContentAccordion
tabsTabsRoot, TabsList, TabsTrigger, TabsContentTabs
popoverPopover, PopoverTrigger, PopoverAnchor, PopoverContent, PopoverClosePopover
dropdown-menuMenu, MenuTrigger, MenuContent, MenuItem, MenuGroup, MenuLabel, MenuSeparatorDropdown Menu
listboxSelectRoot, SelectTrigger, SelectValue, SelectContent, SelectOption, SelectGroupSelect Menu
comboboxCombobox, ComboboxInput, ComboboxContent, ComboboxOption, ComboboxEmptyCombobox
tooltipTooltipRoot, TooltipTrigger, TooltipContentTooltip (JS)
dialogDialogRoot, DialogTrigger, DialogContent, DialogTitle, DialogDescription, DialogCloseSheet
toastcreateToaster, toast, useToasts, ToasterToast
coreuseControllableState, usePosition, useDismiss, useRovingFocus, useTypeahead, focusFirst, composeRefs, mergePropsall of the above

Where the native-first components stand

Select stays a native <select>, Tooltip stays CSS-only, Dialog stays a single file — each with a primitive-based alternative when you outgrow the trade-off (Select Menu, Tooltip (JS), Sheet). Accordion still renders native <details>/<summary> markup — its primitive just moves the open state into React, which is what makes exclusive groups work in every browser. The primitives exist for the interactions the platform doesn't provide, and for composition the data-prop components don't allow.