State Management in Primitives
Relevant source files
The following files were used as context for generating this wiki page:
State management in HX-UI primitives relies on a combination of internal component state, context-based prop drilling, and external data driving. The library distinguishes between behavioral state (managed by underlying Radix UI primitives), visual state (managed via CSS variables and utility classes), and logical state (driven by parent components or hooks).
Behavioral and Component State
HX-UI utilizes Radix UI to handle complex behavioral states such as focus management, keyboard navigation, and ARIA associations. Components like Select, DropdownMenu, and Tabs encapsulate these behaviors while exposing high-level triggers and content containers.
Context-Based Prop Propagation
The Tabs component uses a React Context to synchronize the visual variant ("underline" or "pill") between the TabsList and its child TabsTrigger components. This prevents state mismatch where a trigger might otherwise display a different style than its parent list.
Sources: src/primitives/tabs.tsx:28-76
Data-Driven State Management
For complex layout components like Stepper and DataTable, the library deliberately pushes state management to the caller or external hooks. This architecture ensures that UI components do not become bottlenecks for business logic or data fetching strategies.
External Control in Steppers
The Stepper component does not maintain an internal currentStep state. Instead, it accepts a current index and a steps array from the parent. This allows the step progression to be tied directly to external facts, such as the success of an HTTP request or a WebSocket event.
Sources: src/layout/Stepper.tsx:18-35
DataTable Filtering Logic
The DataTable follows a "non-intrusive" data model where it avoids managing data fetching or sorting internally. However, it provides the useTableSearch hook to bridge the gap between user input and the rendered state.
| Feature | State Responsibility | Implementation Detail |
|---|---|---|
| Data Fetching | Parent Component | DataTable only renders provided rows. |
| Search/Filter | useTableSearch Hook | Computes filtered rows based on query state. |
| Row Selection | Parent via onRowClick | Callback returns the clicked row object to the caller. |
| Loading State | Parent via loading prop | Renders Skeleton components when true. |
Sources: src/layout/DataTable.tsx:23-45, src/layout/DataTable.tsx:165-180
Visual and Transitional States
HX-UI manages visual transitions and feedback states through specific status enums and animation triggers.
The Data Boundary Pattern
The DataBoundary component centralizes the transition logic between four distinct UI states. It enforces a strict priority order to prevent "flashing" incorrect states (e.g., showing "No Data" before the loading state completes).
Sources: src/layout/EmptyState.tsx:90-128
Animation State Identifiers
Visual states for animations are often controlled via data-state attributes provided by Radix or layoutId for Motion components:
- Tabs/Accordion: Use
data-[state=active]ordata-[state=open]to trigger CSS animations for collapsing or highlighting. Sources: src/primitives/tabs.tsx:50, src/primitives/accordion.tsx:75 - SegmentedControl/Stepper: Use
layoutIdto ensure the selection indicator physically slides between items rather than fading in/out, maintaining a continuous visual state. Sources: src/layout/SegmentedControl.tsx:70, src/layout/Stepper.tsx:210
Conclusion
State management in HX-UI primitives is divided between behavioral encapsulation (via Radix UI) and logical transparency. By delegating data-intensive states to hooks like useTableSearch and externalizing progression states in components like Stepper, the library remains flexible across different data fetching architectures.