@cdx-ui/primitives
v0.0.1-beta.107
Published
Unstyled, accessible behavioral components (headless) for the Forge Design System.
Readme
@cdx-ui/primitives
Unstyled, accessible behavioral components (headless) for the Forge Design System.
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 |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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, DialogPopup, DialogClose | Concrete dialog primitives (Root owns open state + context; Trigger/Close use Slot for asChild; Popup owns portal/focus-scope. 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) |
| 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. |
| 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. |
| 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) |
| --------- | ------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------- |
| 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 |
| tile | TileProvider | useTileContext | ITileContextValue, ITileGroupContextValue |
