Fluixi UI
GitHub ↗

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.