@cdx-ui/primitives
v0.3.3
Published

Readme
@cdx-ui/primitives
Unstyled, accessible behavioral components (headless) for the Forge Design System. Tested through @cdx-ui/components; the coverage badge above reflects that suite.
Primitives provide interaction logic, focus management, and accessibility without imposing any visual styling. They serve as the foundation for @cdx-ui/components.
Installation
pnpm add @cdx-ui/primitivesPeer dependencies
react^18.2.0 || ^19.0.0react-native>= 0.76.0 (optional)react-native-reanimated>= 3.0.0 (optional)react-native-web>= 0.19.0 (optional)
Primitives
Concrete behavioral components with built-in interaction state tracking, accessibility (roles, ARIA props, keyboard handling), and context propagation. Each primitive owns behavior that the styled layer (@cdx-ui/components) cannot express with host elements alone.
| Export | Description |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AccordionRoot, AccordionItemRoot, AccordionTriggerRoot, AccordionContentRoot | Concrete accordion primitives (Root owns single/multiple expanded state via @react-stately/disclosure + group context; Item owns per-item open/disabled state, trigger/content id wiring, and item context; Trigger is the toggle Pressable with interaction state + aria-expanded/aria-controls; Content is the collapsible region rendered only when open. Label/Title/Description/Indicator/LeadingSlot/Meta live in @cdx-ui/components) |
| AvatarRoot | Concrete root primitive (context provider for image load state; Image/Text/Icon/Badge live in @cdx-ui/components) |
| ButtonRoot | Concrete root primitive (no sub-slots — Label/Icon/Spinner/Group live in @cdx-ui/components) |
| CheckboxRoot, CheckboxGroup | Concrete checkbox primitives (Root owns controlled state + ARIA + .web split; Group owns group context. Indicator/Icon/Label live in @cdx-ui/components) |
| ChipRoot | Concrete root primitive (View/Pressable union with interaction state + context; Label/Icon/Avatar live in @cdx-ui/components) |
| DialogRoot, DialogTrigger, DialogPortal, DialogOverlay, DialogContent, DialogPopup, DialogClose | Concrete dialog primitives (Root owns open state + context; Trigger/Close use Slot for asChild; Portal mounts children into the shared PortalHost; Overlay is the dismiss backdrop; Content owns FocusScope + ARIA + Escape/back-button dismissal; DialogPopup is the legacy fused panel, kept for back-compat. Header/Title/Description/Content/Footer live in @cdx-ui/components) |
| FieldRoot, FieldLabel | Concrete field primitives (Root provides FormControlContext; Label is platform-split: Text + focus-bridge on native, <label htmlFor> on web; Helper/Error/ErrorIcon live in @cdx-ui/components) |
| FormRoot | Concrete form primitive (platform-split: <form> on web, View on native) |
| InputRoot, InputField | Concrete input primitives (Root owns input context; Field is platform-split: .tsx/.web.tsx/.android.tsx. Slot lives in @cdx-ui/components) |
| LinkRoot | Concrete link primitive (useLink press behavior + ARIA + cross-platform routing) |
| ListItemRoot | Concrete root primitive (View/Pressable union with bespoke asChild merging — interaction state + context; LeadingSlot/Content/Title/Description/Meta/TrailingSlot/SectionHeader live in @cdx-ui/components) |
| useOtpInput, OtpInputField | Headless hook for OTP state machine + concrete per-cell TextInput primitive (focus management, a11y, autofill; styled layer composes Input/HStack on top) |
| ProgressBarRoot, ProgressBarIndicator | Concrete progress primitives (Root owns percent context; Indicator maps percent to width) |
| RadioRoot, RadioGroup | Concrete radio primitives (Root owns interaction + checked state + .web split; Group owns selection contract + group context. Indicator/Label live in @cdx-ui/components) |
| SelectRoot, SelectTrigger, SelectContent, SelectItem | Concrete select primitives (Root owns controlled value/open state; Trigger is platform-split; Content owns FocusScope + keyboard nav; Item owns selection state. Value/Icon/ItemLabel live in @cdx-ui/components) |
| SliderRoot, SliderRail, SliderThumb | Concrete slider primitives (Root owns clamped/snapped value + orientation + keyboard/drag state + context; Rail owns rail-tap-to-seek + track layout; Thumb owns drag gesture + focus. Track/Popup/Marker/MarkerGroup live in @cdx-ui/components) |
| useSwitch | Headless hook for Switch (controlled state + ARIA + interaction tracking; styled layer renders the host element) |
| TileRoot, TileGroup | Concrete tile primitives (Root owns interaction + selection state + per-tile context; Group owns selection contract + group context. LeadingSlot/Content/Title/Description/Indicator/TrailingSlot live in @cdx-ui/components) |
| BreadcrumbsRoot | Concrete breadcrumbs root primitive (navigation context + a11y; styled item/link/separator slots live in @cdx-ui/components) |
| MenuRoot, MenuTrigger, MenuPopup, MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuOverlayRoot | Concrete menu primitives (Root owns open/selection state + context; Trigger/Popup drive anchored-overlay positioning + focus/keyboard nav; Item/CheckboxItem/RadioItem own selection + a11y) |
| TabsRoot, TabsList, Tab, TabPanel | Concrete tabs primitives (Root owns selected-value state + context; List owns roving focus/keyboard nav; Tab is the selectable trigger; Panel is the associated tabpanel region) |
| ToastRoot | Concrete toast root primitive (ToastProvider context + a11y live region; styled slots live in @cdx-ui/components) |
| TooltipRoot, TooltipTrigger, TooltipContent | Concrete tooltip primitives (Root owns open state + context; Trigger owns hover/focus intent; Content is the anchored-overlay bubble with a11y) |
| Date/time & calendar family — the date-field, calendar, range-calendar, month-calendar, date-picker, date-range-picker, month-picker, date-time-field, date-time-list, and date-time-picker modules (e.g. DateFieldRoot, CalendarRoot, DatePickerRoot) | Concrete date/time entry and calendar-grid primitives — segment/selection state, keyboard nav, and ARIA for date fields and calendar grids. See each module's index.ts for its full slot list; styled slots live in @cdx-ui/components |
The tables above summarize the primitive families.
packages/primitives/src/index.tsis the authoritative export list — theoverlaymodule also exports positioning helpers (OverlayContainer,getAnchoredOverlayPosition,useAnchoredOverlay,useDismissOverlay,OverlayStackProvider, z-index constants) beyond those listed below, and the families added above export their own providers/hooks (useBreadcrumbsContext,useMenuContext,useTabsContext/useTabContext,ToastProvider/useToastContext,TooltipProvider/useTooltipContext, and the date/time module contexts).
Utility exports
| Export | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| dataAttributes | Builds data-hover, data-active, data-focus-visible, etc. from an InteractionState object. |
| mergeDataAttributes | Combines multiple data-attribute sources into one spread (prevents overwrites on web). |
| domDataAttributes | Web-specific variant that converts data attributes to DOM-compatible format. |
| mergeDomDataAttributes | Web-specific merge variant for combining DOM data attribute sources. |
| Slot | Primitives-layer asChild implementation — merges props/ref onto the consumer's child element. |
| assignRef | Assigns a value to a callback or object ref (ForwardedRef<T>), handling both forms. |
| createPortalFn | Reference to ReactDOM.createPortal on web, undefined on native (lazy-loaded so native bundles never reference react-dom). |
| useAnchorPosition | Measures an anchor element's on-screen layout (AnchorLayout), with optional remeasure key and per-frame tracking; powers overlay/popup positioning (e.g. Slider.Popup). |
| FormControlContext | Re-exported from @cdx-ui/utils; shared context for field/form control state. |
| useFormControlContext | Re-exported from @cdx-ui/utils; reads FormControlContext in descendant components. |
| OverlayInsetsProvider | Context provider for safe-area insets used by overlay/dialog positioning. |
| Portal, PortalHost | Store-backed portal: Portal registers children into a named host; PortalHost renders them and must be mounted once near the app root (Forge UI's ForgeDesignProvider does this). Used by Dialog, Toast, etc. |
| FullWindowOverlay | iOS wrapper (over react-native-screens) that renders overlays in a separate window above native modals/keyboard; pass-through on Android/web. |
| InteractionState | Type: { hover, focus, active, disabled, focusVisible }. |
| EdgeInsets | Type: { top, right, bottom, left }. |
OTP input utilities
Standalone helper functions re-exported from the otp-input module for custom OTP input implementations:
| Export | Description |
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| applyOtpInputChange(value, index, rawText, cellCount, filter) | Applies a filtered edit at index and returns { nextValue, focusIndex }. |
| filterDigits(text) | Filters a string to digits only (0–9). |
| filterAllowedCharacters(allowed) | Returns a (text) => string filter that keeps characters present in allowed. |
| filterByRegExp(pattern) | Returns a (text) => string filter that keeps characters matching pattern (per code unit). |
Context hooks and providers
Several modules export context providers and hooks for reading component state from descendant sub-components or for integrating with external systems (e.g., routing).
| Module | Provider(s) | Hook(s) | Context value type(s) |
| --------- | -------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------- |
| accordion | AccordionProvider, AccordionItemProvider | useAccordionContext, useAccordionItemContext | IAccordionContextValue, IAccordionItemContextValue |
| avatar | — | useAvatarContext | IAvatarContextValue |
| button | — | useButtonContext | InteractionState |
| checkbox | — | useCheckboxContext | ICheckboxContextValue |
| chip | — | useChipContext | InteractionState |
| dialog | DialogProvider | useDialog | IDialogContextType |
| input | — | useInputContext | — |
| link | LinkProvider, LinkInteractionProvider | useLink, useLinkInteractionContext | LinkConfig, LinkInteractionState |
| list-item | ListItemProvider | useListItemContext | InteractionState |
| otp-input | OtpInputProvider, OtpCellIndexProvider | useOtpInputContext, useOtpCellIndexContext | OtpInputContextValue, OtpInputCellIndexContextValue |
| progress | — | useProgressContext | ProgressContextValue |
| radio | — | useRadioContext | IRadioContextValue |
| select | — | useSelectContext, useSelectItemContext | SelectContextValue, SelectItemInteractionState |
| slider | — | useSliderContext | SliderContextValue |
| tile | TileProvider | useTileContext | ITileContextValue, ITileGroupContextValue |
License
MIT © 2026 Digital First Holdings LLC. The full license text ships in the package as LICENSE.
