CrystalFlow provides individual components that can be composed to build custom workflow UIs.
NodePalette
Sidebar component displaying available node types.
function NodePalette(props: NodePaletteProps): JSX.Element;
Props:
Array of node classes to display.
onNodeSelect
(nodeClass: typeof Node) => void
Callback when a node is selected/added.
Show search input to filter nodes.
Example:
import { NodePalette } from '@crystalflow/react';
import { AddNode, MultiplyNode } from './nodes';
<NodePalette
nodeTypes={[AddNode, MultiplyNode]}
onNodeSelect={(NodeClass) => {
console.log('Selected:', NodeClass);
}}
searchable={true}
groupByCategory={true}
/>
PropertyPanel
Sidebar component for editing node properties.
function PropertyPanel(props: PropertyPanelProps): JSX.Element;
Props:
Currently selected node to display properties for.
onPropertyChange
(nodeId: string, property: string, value: any) => void
Callback when a property value changes.
Example:
import { PropertyPanel } from '@crystalflow/react';
<PropertyPanel
selectedNode={selectedNode}
onPropertyChange={(nodeId, property, value) => {
console.log(`Node ${nodeId}.${property} = ${value}`);
updateNodeProperty(nodeId, property, value);
}}
/>
WorkflowCanvas
React Flow canvas component for rendering the workflow.
function WorkflowCanvas(props: WorkflowCanvasProps): JSX.Element;
Props:
Callback when a node is clicked.
Callback when empty canvas area is clicked.
Example:
import { WorkflowCanvas } from '@crystalflow/react';
<WorkflowCanvas
workflow={workflow}
onNodeClick={(node) => {
console.log('Clicked node:', node.id);
setSelectedNode(node);
}}
onCanvasClick={() => {
setSelectedNode(null);
}}
/>
Toolbar component with common actions.
function Toolbar(props: ToolbarProps): JSX.Element;
Props:
Whether workflow is currently executing.
Example:
import { Toolbar } from '@crystalflow/react';
<Toolbar
onExecute={handleExecute}
onSave={handleSave}
onLoad={handleLoad}
onClear={handleClear}
isExecuting={isExecuting}
/>
CustomNode
Custom React Flow node renderer.
function CustomNode(props: NodeProps): JSX.Element;
Props:
Node data including metadata and values.
Whether node is selected.
This component is automatically used by WorkflowCanvas and typically doesn’t need to be used directly.
ExecutionProgress
Component showing workflow execution progress.
Work in Progress: This component is currently being implemented.
import { ExecutionProgress } from '@crystalflow/react';
<ExecutionProgress
isExecuting={isExecuting}
progress={progress}
currentNode={currentNode}
/>
ErrorDisplay
Component for displaying execution errors.
Work in Progress: This component is currently being implemented.
import { ErrorDisplay } from '@crystalflow/react';
<ErrorDisplay error={error} onDismiss={() => setError(null)} />
Complete Custom UI Example
Build a custom workflow UI by composing components:
import React, { useState } from 'react';
import {
NodePalette,
PropertyPanel,
WorkflowCanvas,
Toolbar,
useWorkflow,
useExecution
} from '@crystalflow/react';
import { AddNode, MultiplyNode, DisplayNode } from './nodes';
function CustomWorkflowUI() {
const [selectedNode, setSelectedNode] = useState(null);
const { workflow, addNode, updateNodeData, clear } = useWorkflow();
const { execute, isExecuting, result } = useExecution();
const nodes = [AddNode, MultiplyNode, DisplayNode];
const handleNodeSelect = (NodeClass) => {
const node = addNode(NodeClass, {
position: { x: 300, y: 300 }
});
setSelectedNode(node);
};
const handlePropertyChange = (nodeId, property, value) => {
updateNodeData(nodeId, { [property]: value });
};
const handleExecute = async () => {
await execute(workflow);
};
return (
<div className="custom-ui">
<Toolbar
onExecute={handleExecute}
onClear={clear}
isExecuting={isExecuting}
/>
<div className="main-area">
<NodePalette
nodeTypes={nodes}
onNodeSelect={handleNodeSelect}
/>
<WorkflowCanvas
workflow={workflow}
onNodeClick={setSelectedNode}
onCanvasClick={() => setSelectedNode(null)}
/>
<PropertyPanel
selectedNode={selectedNode}
onPropertyChange={handlePropertyChange}
/>
</div>
{result && (
<div className="results">
<h3>Execution Result</h3>
<pre>{JSON.stringify(result, null, 2)}</pre>
</div>
)}
</div>
);
}
export default CustomWorkflowUI;
Styling Components
All components accept className and style props:
<NodePalette
nodeTypes={nodes}
onNodeSelect={handleSelect}
className="my-palette"
style={{ width: '250px', backgroundColor: '#f5f5f5' }}
/>