npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sonata-innovations/fiber-fbre

v5.0.0

Published

Fiber Render Engine — renders Flow JSON forms with conditional logic, validation, and screen transitions

Readme

@sonata-innovations/fiber-fbre

Fiber Render Engine — consumes Flow JSON and renders data collection forms. Handles conditional logic, validation, calculations, screen transitions, theming, and outputs collected FlowData back to the parent application. Renders 30 component types across ten form styles; zero UI-framework dependency (custom CSS only).

Quick Start

Local Mode

Pass a Flow object directly:

import { FBRE } from "@sonata-innovations/fiber-fbre";
import "@sonata-innovations/fiber-fbre/styles";

function App() {
  return (
    <FBRE
      flow={myFlow}
      screenIndex={0}
      onFlowComplete={(data) => console.log(data)}
    />
  );
}

Remote Mode

Fetch a published flow from a Fiber API:

import { FBRE } from "@sonata-innovations/fiber-fbre";
import "@sonata-innovations/fiber-fbre/styles";

function App() {
  return (
    <FBRE
      flowId="your-flow-id"
      apiEndpoint="https://your-api.example.com/api/v1"
      apiKey="your-api-key"
      onFlowComplete={(data) => console.log(data)}
    />
  );
}

Server-Driven Mode

Session-based rendering where the server evaluates conditions and validation:

import { FBRE } from "@sonata-innovations/fiber-fbre";
import "@sonata-innovations/fiber-fbre/styles";

function App() {
  return (
    <FBRE
      sessionEndpoint="https://your-api.example.com/api/v1/public/sessions"
      flowId="your-flow-id"
      onFlowComplete={(data) => console.log(data)}
    />
  );
}

Installation

npm install @sonata-innovations/fiber-fbre

Then import the CSS once in your app entry point — without it the form renders unstyled:

import "@sonata-innovations/fiber-fbre/styles";

Peer dependencies: react ^18.0.0 || ^19.0.0, react-dom ^18.0.0 || ^19.0.0

Runtime dependencies: zustand, @sonata-innovations/fiber-types, @sonata-innovations/fiber-shared

Documentation

This README covers evaluation and day-to-day API lookup. Deeper guides ship inside the package under docs/ (and an AGENTS.md routing guide at the package root), and are browsable in the public docs mirror at github.com/sonata-innovations/fiber-docs.

| Topic | In package | Mirror | |-------|-----------|--------| | Concepts overview | docs/fiber-concepts.md | fiber-concepts.md | | FBRE integration guide | docs/integration/fbre.md | integration/fbre.md | | Theming reference | docs/features/fbre-theming.md | features/fbre-theming.md | | Confirmation screen | docs/features/confirmation-screen.md | features/confirmation-screen.md |

Schema references (Flow input and FlowData output) ship in the @sonata-innovations/fiber-types package under docs/schema/, and are mirrored at:

API

<FBRE /> Props

FBRE supports three rendering modes, selected by which props you pass. The modes are mutually exclusive.

Local Mode

Render a Flow object you already have in memory.

| Prop | Type | Required | Description | |------|------|----------|-------------| | flow | Flow | Yes | Flow JSON object | | data | FlowData | No | Pre-populated form data (not reactive — read once at mount) | | screenIndex | number | No | Initial screen index (default 0) | | themeDefaults | ThemeConfig | No | Theme defaults merged under flow.config.theme — the flow wins | | theme | ThemeConfig | No | Theme overrides merged over flow.config.theme — the prop wins | | navigation | NavigationConfig | No | Override navigation settings (merged over flow.config.navigation) | | controls | ControlsConfig | No | Override controls settings (merged over flow.config.controls) | | context | Record<string, string \| boolean \| number> | No | External context values for condition evaluation and calculations | | storeRef | MutableRefObject<StoreApi<FBREStoreState> \| null> | No | Ref to access the Zustand store | | onFlowComplete | (data: FlowData) => void \| ConfirmationResult \| Promise<void \| ConfirmationResult> | Yes | Called when the user completes the flow. Return/resolve a ConfirmationResult to override the configured confirmation message; a rejected Promise surfaces a completion error | | onScreenChange | (index: number, data: FlowData) => void | No | Called on screen navigation |

Remote Mode

Fetch a published flow from a Fiber API by ID.

| Prop | Type | Required | Description | |------|------|----------|-------------| | flowId | string | Yes | ID of the published flow | | apiEndpoint | string | Yes | Base URL of the Fiber API | | apiKey | string | No | API key for authentication | | data | FlowData | No | Pre-populated form data (not reactive) | | screenIndex | number | No | Initial screen index (default 0) | | theme | ThemeConfig | No | Override theme settings | | navigation | NavigationConfig | No | Override navigation settings | | controls | ControlsConfig | No | Override controls settings | | context | Record<string, string \| boolean \| number> | No | External context values for condition evaluation and calculations | | storeRef | MutableRefObject<StoreApi<FBREStoreState> \| null> | No | Ref to access the Zustand store | | onFlowComplete | (data: FlowData) => void \| ConfirmationResult \| Promise<void \| ConfirmationResult> | Yes | Called when the user completes the flow (see Local Mode) | | onScreenChange | (index: number, data: FlowData) => void | No | Called on screen navigation |

Server-Driven Mode

Session-based rendering. The server evaluates conditions and validation; the client renders one screen at a time. On completion it resets the submit button and shows a terminal confirmation (from config.confirmation, else a generic "Thank you"; an explicit show: false renders nothing); onFlowComplete still fires with the server result if you want to drive your own post-completion UI.

| Prop | Type | Required | Description | |------|------|----------|-------------| | sessionEndpoint | string | Yes | Session API base URL | | flowId | string | Yes | ID of the flow to start a session for | | apiKey | string | No | API key for authentication | | theme | ThemeConfig | No | Override theme settings | | context | Record<string, string \| boolean \| number> | No | External context values for condition evaluation and calculations | | onFlowComplete | (data: FlowData) => void | Yes | Called when the user completes the flow | | onScreenChange | (screenNumber: number) => void | No | Called on screen navigation (receives screen number, not index + data) |

Imperative Access

Access the store directly for programmatic control:

import { useFBREStore, useFBREStoreApi, useFBREApi } from "@sonata-innovations/fiber-fbre";

// Inside a child of <FBRE />
const flowData = useFBREStore((s) => s.getFlowData());
const storeApi = useFBREStoreApi();
const data = storeApi.getState().getFlowData();

// In remote mode — access API config, flowId, tenantId
const apiContext = useFBREApi();

getMaxScreenIndex() on the store returns the maximum screen index (screen count − 1). (Renamed from getMaxScreenCount, whose name implied a count.)

Events

import { addFBREEventListener, removeFBREEventListener } from "@sonata-innovations/fiber-fbre";

const handler = (id, data) => console.log("file uploaded:", id, data);
addFBREEventListener("file-upload", handler);
removeFBREEventListener("file-upload", handler);

Note: the file-upload event bus is module-global — a listener fires for uploads from every <FBRE /> instance on the page, not just one. Filter by the emitted component id if you run multiple instances.

Exports

// Component
import { FBRE } from "@sonata-innovations/fiber-fbre";

// Store hooks
import { useFBREStore, useFBREStoreApi, useFBREApi } from "@sonata-innovations/fiber-fbre";

// Event system
import { addFBREEventListener, removeFBREEventListener } from "@sonata-innovations/fiber-fbre";

// Brand-font loading (FBRE calls ensureFontLoaded itself; exported for hosts
// that want the face registered before first paint)
import { ensureFontLoaded, fontFamilyStack } from "@sonata-innovations/fiber-fbre";

// Error classes
import { ApiError, TimeoutError } from "@sonata-innovations/fiber-fbre";

// Types — props, store, and the full Flow/FlowData/Component type surface
import type {
  FBREProps,
  FBRELocalProps,
  FBRERemoteProps,
  FBREServerDrivenModeProps,
  FBREStoreState,
  FBREApiConfig,
  Flow,
  FlowScreen,
  FlowConfiguration,
  ThemeConfig,
  NavigationConfig,
  ControlsConfig,
  FontFamilyConfig,
  ConfirmationConfig,
  ConfirmationResult,
  Component,
  ComponentProperties,
  FlowData,
  ScreenData,
  ComponentData,
  FileUploadData,
  FlowConditionConfig,
  ConditionOperator,
  // …plus per-component property types and condition/rule types
} from "@sonata-innovations/fiber-fbre";

Flow schema, conditions, validation, calculations

The Flow JSON hierarchy (Flow → Screen → Component), all 30 component types, the 19 condition operators, the 17 validators, calculation formulas, and inline markup are documented in the schema references — docs/schema/ in @sonata-innovations/fiber-types, mirrored at schema/flow-schema.md (with a quick reference).

A few runtime facts worth knowing up front:

  • No auto-migration. The flat required / regex properties were removed from the schema in @sonata-innovations/fiber-types 4.0.0 and are ignored if present — an un-migrated field renders with no required marker and no enforcement. Pre-migrate flows to validation.rules (and conditions) before passing them to FBRE.
  • Calculation formulas use single braces to reference component values: {uuid}. They support arithmetic, comparisons, IF(), aggregation (SUM/COUNT/AVG/MIN/MAX over repeaters), and update reactively.
  • Condition and validation results live on the store (conditionResults, validationErrors), not in the Flow JSON. Components hidden by a condition are excluded from FlowData and don't block screen validity.

Confirmation Screen

A terminal "thank you" screen shown after submission, configured on the flow (config.confirmation) rather than as a Screen. It replaces the final screen and hides the controls/stepper; title/body support reference markup (collected fields, calculations, and context values by name). onFlowComplete decides when it shows — return void for immediate, a Promise to keep the submit button in-flight until it settles, or a ConfirmationResult ({ title?, body? }) to override the configured message (e.g. with a server reference number).

In local and remote modes there is no generic fallback: a flow with no config.confirmation completes without any visible acknowledgement, so configure one if the page should acknowledge the submit. (Server-driven mode does fall back, because the renderer there is often the whole page.) A flow can only be submitted once — after a successful completion the controls are disabled even when no confirmation renders, and a rejected promise re-enables them for a retry. Full guide: features/confirmation-screen.md.

Style Families & Advance Behaviors

There is no presentation mode — the look is the style, and the two advance behaviors are navigation flags.

Four of the ten styles form the focused family: centered-minimal, stacked-cards, soft-float, bold-statement. On top of their own look they center content in a narrow column, fade/scale/stagger components in on transitions (respecting prefers-reduced-motion), and enlarge type and tap targets. The other six — clean, outlined, refined-clean, airy-clean, soft-outlined, defined-outlined — are the form family. The vocabulary is flat: any style works on any flow. FBRE derives the family and emits it as data-style-family; styleFamily() and FOCUSED_STYLES are exported for grouping a style picker.

navigation.autoAdvance (default off) advances ~500ms after a single-select choice. navigation.advanceOnEnter (default on) advances on Enter in a text or number field. Both only fire when a screen renders exactly one interactive component (display-only and condition-hidden components don't count), never on the last screen, and never on an invalid screen; Enter-to-advance also stands down inside an open popup, so the colour picker's hex field commits on Enter instead of skipping the screen.

FlowData output, conditions, validation, calculations, transitions, and dark mode are unaffected by any of this. Full guide: features/style-families.md.

Upgrading from 3.x: config.mode and the mode prop are gone. A "conversational" flow already carried a focused style, so its look is unchanged — add navigation: { autoAdvance: true } to keep the auto-advance.

Theming

FBRE's appearance is driven entirely by --fbre-* CSS custom properties. Two independent axes: theme.style controls shape (borders vs. underlines, fills, spacing), and the palette controls colors. There are three ways to set the palette, and they layer — each overrides the one before, so you specify only what you want to change:

  1. colorScheme presettheme.colorScheme ("light" default | "dark") seeds the entire token set with a coherent palette and sets data-mode on the container. (Replaces the former darkMode boolean; there is no runtime fallback — migrate stored flows.)
  2. Palette knobstheme.{color, background, surface, text, border, radius, fontFamily, error, success, warning} set their primary token plus the tokens derived from it (e.g. surface also drives input fills and hover/alt surfaces). Any subset; unset knobs fall through to the preset.
  3. Raw --fbre-* CSS — override any token directly (including ones with no knob, like --fbre-star-filled) by scoping rules to your wrapper.
<FBRE
  flow={myFlow}
  theme={{ colorScheme: "dark", color: "#bcd3cd", surface: "#243244", radius: "3px" }}
  onFlowComplete={handleComplete}
/>

Brand fonts. theme.fontFamily also accepts { family, src, faces?, stack? }. Given sources, FBRE registers the @font-face in the owning document rather than assuming the host page already loaded the family — which is the only thing that works inside a shadow root, where a face declared in the root's stylesheet is never registered. A plain string stays correct when the host page loads the font itself.

Defaults worth noting: --fbre-radius is 4px and --fbre-font is "Segoe UI", system-ui, -apple-system, sans-serif. The complete token catalog with light/dark defaults is in features/fbre-theming.md.

Screen Transitions

Animate screen changes by setting navigation.transition in the flow config:

{ "config": { "navigation": { "transition": "slideFade" } } }

| Type | Effect | Direction-aware? | |------|--------|-----------------| | "none" | Instant swap (default) | — | | "slide" | Full horizontal slide | Yes | | "fade" | Crossfade | No | | "slideFade" | 30px slide + opacity | Yes | | "rise" | Vertical rise/sink | Yes | | "scaleFade" | Scale + opacity | No |

Direction-aware transitions reverse when navigating backward; buttons are disabled mid-animation to prevent overlap. Customize timing via --fbre-transition-duration / --fbre-transition-easing. @media (prefers-reduced-motion: reduce) sets the duration to 0ms automatically.

FlowData Output

getFlowData() returns the collected form data, mirroring the Flow structure (Flow → ScreenData → ComponentData, with components?: ComponentData[][] for groups and repeaters). Display-only components — header, text, divider, callout, table — are excluded automatically; computed fields are included. Full shape and field semantics: schema/flow-data-schema.md.

Responsive Sizing

FBRE uses CSS container queries to automatically scale controls in narrow containers (under 400px). Buttons, stepper dots, and toggle switches shrink proportionally — no configuration needed; just embed in a smaller container and the compact sizing kicks in.

Multiple Instances

Each <FBRE /> creates its own isolated Zustand store, so multiple instances run simultaneously on the same page without state conflicts. (The one exception is the module-global file-upload event bus noted under Events.)

<FBRE flow={flowA} onFlowComplete={handleA} />
<FBRE flow={flowB} onFlowComplete={handleB} />

License

MIT