@cdx-ui/primitives
v0.0.1-beta.179
Published

Readme
@cdx-ui/primitives
Unstyled, accessible behavioral components (headless) for the Forge Design System. Tested through @cdx-ui/components — see Coverage.
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) |
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, change, position) | Applies a character change (insert, delete, replace) to an OTP value string. |
| filterDigits(text) | Filters a string to digits only (0–9). |
| filterAllowedCharacters(text, allowed) | Filters a string to characters matching a provided set. |
| filterByRegExp(text, pattern) | Filters a string to characters matching a regular expression. |
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 | IInputContextValue |
| link | LinkProvider, LinkInteractionProvider | useLink, useLinkInteractionContext | LinkConfig, LinkInteractionState |
| list-item | ListItemProvider | useListItemContext | InteractionState |
| otp-input | OtpInputProvider, OtpCellIndexProvider | useOtpInputContext, useOtpCellIndexContext | OtpInputContextValue, OtpInputCellIndexContextValue |
| progress | — | useProgressContext | ProgressContextValue |
| radio | RadioProvider | useRadioContext | IRadioContextValue |
| select | — | useSelectContext, useSelectItemContext | ISelectContextValue, ISelectItemContextValue |
| slider | — | useSliderContext | SliderContextValue |
| tile | TileProvider | useTileContext | ITileContextValue, ITileGroupContextValue |
License
MIT © 2026 Digital First Holdings LLC. See LICENSE for details.
