kit
SSR-safe utilities and primitives for building Fluixi UI components.
Layer 1 of the Fluixi headless UI ecosystem: the low-level utilities that every primitive and component is built from. It contains no UI — only the reusable behavior that components must never re-implement.
@fluixi/kit builds on @fluixi/core for reactivity, context, control flow and
prop handling, and reuses the framework's generic helpers (@fluixi/utils)
rather than duplicating them. @fluixi/core is the only peer dependency.
Architecture
The package is a flat set of focused modules, each independently importable so consumers only pay for what they use:
| Module | Import | Responsibility |
|---|---|---|
| reactive | @fluixi/kit/reactive |
access, controlled/uncontrolled signals |
| props | @fluixi/kit/props |
default-aware, reactivity-preserving prop merging; splitProps |
| context | @fluixi/kit/context |
safe/optional context factories |
| id | @fluixi/kit/id |
stable unique id generation |
| ref | @fluixi/kit/ref |
callback/object ref merging |
| events | @fluixi/kit/events |
event-handler composition |
| keyboard | @fluixi/kit/keyboard |
key constants and classification |
| pointer | @fluixi/kit/pointer |
virtual/assistive event detection |
| a11y | @fluixi/kit/a11y |
ARIA/data attribute helpers, visually-hidden styles |
| dom | @fluixi/kit/dom |
SSR-safe DOM queries, focusable traversal |
| platform | @fluixi/kit/platform |
environment and user-agent detection |
| cleanup | @fluixi/kit/cleanup |
callback chaining, disposal scopes |
| types | @fluixi/kit/types |
shared type utilities |
Everything is re-exported from the package root (@fluixi/kit).
Key building blocks
Controlled / uncontrolled state
createControllableSignal is the foundation for every interactive component. A
component can be driven by a value/onChange pair (controlled) or manage its
own state from a defaultValue (uncontrolled), with one consistent API:
import { createControllableSignal } from '@fluixi/kit/reactive';
const [value, setValue] = createControllableSignal<string>({
value: () => props.value,
defaultValue: () => props.defaultValue,
onChange: (v) => props.onChange?.(v),
});
onChange fires only when the value actually changes, and internal state is left
untouched while the component is controlled.
Default-aware prop merging
mergeDefaultProps applies defaults without clobbering: an explicit undefined
falls back to the default, and reactivity is preserved because the underlying
mergeProps re-reads each source on access.
import { mergeDefaultProps } from '@fluixi/kit/props';
props = mergeDefaultProps({ size: 'md', type: 'button' }, props);
Safe context
createSafeContext returns a provider, a typed reader that throws a descriptive
error when used outside its provider, and the raw context for advanced cases.
Accessibility
The a11y, keyboard and pointer modules encode behavior the WAI-ARIA patterns
depend on: presence-style data-* attributes, aria-checked="mixed" for
tri-state controls, activation/navigation key classification, and detection of
assistive-technology-generated events so components can respond correctly to
screen-reader interaction.
Performance
- Side-effect free (
"sideEffects": false) and split into subpath exports for precise tree-shaking. - Pure functions and lazy platform checks — no work runs at import time.
- DOM and platform helpers are SSR-safe and never touch globals on the server.
Extension points
Each module is the single source of truth for its behavior. Layer 2 primitives (focus management, dismissable layers, roving focus) and Layer 5 components compose these utilities instead of re-implementing them.
Part of the Fluixi UI component library. Made with ☕ by the Fluixi team.