Lit WebComponents vs. React for xyflow

Building node-based UIs with xyflow can be done using its framework-specific wrappers (React Flow, Svelte Flow) or by using the headless @xyflow/system core with other libraries like Lit. This document explores the benefits and trade-offs of using Lit WebComponents compared to the standard React implementation.

🌟 Why Lit?

Lit is a lightweight library for building fast, lightweight WebComponents. When paired with xyflow, it offers a unique set of advantages:

1. Framework Agnosticism

WebComponents are a web standard. A <lit-flow> component can be used in any environment:

This makes Lit an excellent choice for building a flow editor that needs to be embedded in diverse technical stacks.

2. Performance & Bundle Size

3. Encapsulation (Shadow DOM)

4. Documentation & Static Usage

One of the standout use cases for the Lit implementation is embedded documentation.


⚡ State Management & Lit Signals

One of the most significant differences between the React and Lit implementations is how state changes propagate through the graph.

React Flow (Zustand)

React Flow uses zustand for state management. While highly efficient, React's top-down rendering model often means that a change in one part of the graph (like moving a node) can trigger re-renders or reconciliation checks across many components unless carefully optimized with memo and specific selectors.

Lit + xyflow (Lit Signals)

By using @lit-labs/signals, we achieve fine-grained reactivity:


🛠️ Declarative vs. Imperative Interactivity

React Flow

Interactivity is largely declarative through props. If you want to disable dragging, you pass nodesDraggable={false}. React Flow handles the internal state and event listener cleanup.

Lit + xyflow

The Lit implementation mirrors this declarative approach with attributes (nodes-draggable="false"), but it also provides a more imperative-friendly API. Because the component is a real DOM element, you can interact with it directly via JavaScript:

const flow = document.querySelector('lit-flow');
flow.nodes = [...]; // Direct property access
flow.addEventListener('connect', (e) => { ... }); // Standard DOM events

This makes it much easier to integrate with non-React tools or legacy systems.


📦 Publishing & Distribution

React Flow

Distributing a React-based flow component usually requires the consumer to also be using React. If you want to share it with a team using Vue, you often have to build a complex wrapper or maintain multiple versions of the same logic.

Lit + xyflow

Because LitFlow is a standard WebComponent, it can be published as a single, minified JS bundle.


🎨 Material 3 & Design Tokens

LitFlow is built with Material 3 principles from the ground up.


📊 Comparison Table

Feature Lit + xyflow React Flow
Bundle Size ~30KB (minified/gzipped) ~150KB+ (React + Zustand + RF)
Reactivity Fine-grained (Signals) Component-level (Zustand/Hooks)
Interoperability Universal (WebComponent) React-only
Styling M3 Tokens / Shadow DOM CSS / Styled Components
Subflows Manual orchestration Built-in
Static Docs Native attributes Prop-based
Learning Curve Moderate (Web Standards) Low (if you know React)

✅ Pros & ❌ Cons

Lit + xyflow

Pros:

Cons:

React Flow

Pros:

Cons:

🎯 Conclusion

Use Lit + xyflow if you are building a library that needs to be shared across different teams/frameworks, or if you are extremely sensitive to bundle size and performance.

Use React Flow if you are already in a React environment and want to move fast by leveraging a mature, feature-complete ecosystem.