Skip to content
D
Documentation

@grafloria/react

reference
10 min readUpdated

React bindings for Grafloria Diagrams and Grafloria Dashboards — an MIT diagram and dashboard engine: routing, auto-layout, undo, collaboration and dashboard layouts, native in React.

Install

bash
npm install @grafloria/react @grafloria/engine @grafloria/renderer react react-dom @grafloria/element

It expects these alongside it:

  • @grafloria/engine ^0.3.0
  • @grafloria/renderer ^0.4.16
  • react ^17.0.0 || ^18.0.0 || ^19.0.0
  • react-dom ^17.0.0 || ^18.0.0 || ^19.0.0
  • @grafloria/element ^0.4.3

Functions

createGrafloriaStore

ts
function createGrafloriaStore(): GrafloriaStore

GrafloriaCommentPanel

ts
function GrafloriaCommentPanel(props: GrafloriaCommentPanelProps)

Props

NameTypeDefaultDescription
storeCommentStore
options?CommentPanelOptions
onSelect?(threadId: string) => void
className?string
style?CSSProperties

Events

  • onSelect

GrafloriaDashboard

ts
function GrafloriaDashboard(props: GrafloriaDashboardProps)

Props

NameTypeDefaultDescription
views?DashboardViewSpec[]Multi-view (tabbed) board. Mutually exclusive with widgets.
widgets?DashboardWidgetSpec[]Single-view shorthand.
options?Partial<DashboardOptions>Board options: columns, gap, sizing, rtl, responsive, binder…
widgetTypes?WidgetTypesMaps a widget kind to the React component that renders it.
activeView?stringThe visible view (the tab pattern). Omit for kit-managed.
layout?"grid" | "split"LIVE SWITCHES — the toolbar toggles as props. Each is applied at mount
sizing?"fit" | "grow"
static?booleanStatic board: the viewer's mode — no drag, no resize, no handles.
onReady?(handle: DashboardHandle) => voidThe typed handle, once the board is live.
onLayoutChange?(change: { viewId: string; widgets: DashboardWidgetSpec[]; }) => voidMirrors the kit's committed gestures (drag, resize, add, remove).
className?string
style?CSSProperties
children?ReactNode

Events

  • onReady — The typed handle, once the board is live.
  • onLayoutChange — Mirrors the kit's committed gestures (drag, resize, add, remove).

GrafloriaDiagram

ts
function GrafloriaDiagram(props: GrafloriaDiagramProps)

Props

NameTypeDefaultDescription
specRenderSpecAny kit spec — erDiagram(...), umlDiagram(...), dashboard(...), or DSL text.
options?RenderOptionsOptions passed through to the underlying createDiagram.
onReady?(instance: DiagramInstance) => void
className?string
style?CSSProperties

Events

  • onReady

GrafloriaFlow

ts
function GrafloriaFlow(props: GrafloriaFlowProps)

Props

NameTypeDefaultDescription
nodes?NodeSpec[]Controlled nodes. Provide with onNodesChange (see useNodesState).
edges?EdgeSpec[]Controlled edges.
groups?(GroupModel | GroupSpec)[]Controlled groups — zones around some nodes (a spec's groups, or the live
defaultNodes?NodeSpec[]Uncontrolled nodes — the instance owns them from here on.
defaultEdges?EdgeSpec[]
defaultGroups?(GroupModel | GroupSpec)[]
onNodesChange?(nodes: NodeModel[]) => void
onEdgesChange?(edges: LinkModel[]) => void
onSelectionChange?(change: { nodes: NodeModel[]; edges: LinkModel[]; }) => void
onConnect?(change: { link: LinkModel; }) => void
onNodeClick?(change: { node: NodeModel; world: { x: number; y: number; }; }) => void
onEdgeClick?(change: { edge: LinkModel; world: { x: number; y: number; }; }) => void
onInit?(instance: DiagramInstance) => void
nodeTypes?NodeTypesCustom node components, keyed by node type.
theme?Theme
fitView?boolean
enablePan?boolean
enableZoom?boolean
zoomSensitivity?number
dragThreshold?number
readonly?boolean
minZoom?number
maxZoom?number
ssr?{ html: string; snapshot: HydrationSnapshot; }The renderToStaticSVG() result. Renders server-side, hydrates client-side.
layout?string | { name: string; options?: Record<string, unknown>; }Declarative auto-layout — any engine registry name ('elk', 'dagre',
onLayoutDone?(result: unknown) => voidFires after each declarative layout completes.
plugins?boolean | CanvasPluginOptionsCanvas plugins — true mounts minimap + zoom/fit controls + background
collab?GrafloriaCollabOptionsReal-time collaboration: hand in a transport (BroadcastChannelTransport,
onCollabReady?(session: SyncAdapter) => voidThe live SyncAdapter, right after join().
comments?boolean | CommentStoreAnchored comment threads — true creates a store, or pass a shared
commentsViewer?stringViewer id for a comments: true-created store.
rendererConfig?Record<string, unknown>Renderer config passthrough (parallelLinks, parallelSpacing, jump styles, …).
interaction?Record<string, unknown>Interaction config passthrough (portVisibility, enableHelperLines, …).
tokenBridge?unknownDesign-token bridge — adopt the app's shadcn / MUI / Tailwind CSS variables.
highlighterConfig?boolean | Partial<HighlighterConfig>The outline layer Angular's canvas draws: outlines around the hovered node,
highlightConnected?boolean | HighlightConnectedOptionsBring the selected nodes' lines forward and fade the rest: true, or
className?string
style?CSSProperties
children?ReactNodeOverlays (toolbars, panels). Rendered as siblings of the canvas.

Events

  • onNodesChange
  • onEdgesChange
  • onSelectionChange
  • onConnect
  • onNodeClick
  • onEdgeClick
  • onInit
  • onLayoutDone — Fires after each declarative layout completes.
  • onCollabReady — The live SyncAdapter, right after join().

GrafloriaProvider

Wrap anything that needs useGrafloria() outside of <GrafloriaFlow>'s subtree.

tsx
<GrafloriaProvider>
  <Toolbar />           // useGrafloria() works here…
  <GrafloriaFlow … />       // …because the flow publishes its instance to the store
</GrafloriaProvider>

<GrafloriaFlow> also creates its own store when there is no provider, so the simple single-canvas case needs no wrapper at all.

ts
function GrafloriaProvider({ children }: GrafloriaProviderProps)

Props

NameTypeDefaultDescription
children?ReactNode

useEdgesState

Controlled edge state. Mirrors {@link useNodesState}.

ts
function useEdgesState(initial: EdgeSpec[] = []): EdgesState

useGrafloria

The live DiagramInstance, or null until <GrafloriaFlow> has mounted.

Works from anywhere inside an <GrafloriaProvider> (a toolbar, a minimap, a sidebar) and from inside <GrafloriaFlow>'s own children.

tsx
const grafloria = useGrafloria();
<button onClick={() => grafloria?.fitView()}>Fit</button>
ts
function useGrafloria(): DiagramInstance | null

useGrafloriaStore

The nearest store, or null when there is no provider above us.

ts
function useGrafloriaStore(): GrafloriaStore | null

useNodesState

Controlled node state — the React Flow tuple everyone already knows:

tsx
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
<GrafloriaFlow nodes={nodes} onNodesChange={onNodesChange} … />

onNodesChange is what closes the loop: the user drags a node, the ENGINE moves it, the instance emits nodes:change, <GrafloriaFlow> calls this, and React state catches up. Without it a controlled <GrafloriaFlow> would snap the node back on the next render — the classic controlled-component trap.

ts
function useNodesState(initial: NodeSpec[] = []): NodesState

useOnSelectionChange

Fire a callback whenever the selection changes.

tsx
useOnSelectionChange(({ nodes }) => setInspected(nodes[0] ?? null));

The handler is held in a ref, so passing an inline arrow (the common case) does NOT re-subscribe on every render.

ts
function useOnSelectionChange(handler: (change: SelectionChange) => void): void

useSelection

The current selection as state (for rendering an inspector panel).

ts
function useSelection(): SelectionChange

useViewport

The live camera (zoom + world rect) as state — for a minimap or a zoom badge.

ts
function useViewport(): { zoom: number; x: number; y: number }

Constants

GrafloriaContext

ts
const GrafloriaContext: any

Interfaces

GrafloriaCommentPanelProps

ts
interface GrafloriaCommentPanelProps

Properties

NameTypeDefaultDescription
storeCommentStore
options?CommentPanelOptions
onSelect?(threadId: string | null)
className?string
style?CSSProperties

GrafloriaDashboardProps

ts
interface GrafloriaDashboardProps

Properties

NameTypeDefaultDescription
views?DashboardViewSpec[]Multi-view (tabbed) board. Mutually exclusive with widgets.
widgets?DashboardWidgetSpec[]Single-view shorthand.
options?Partial<DashboardOptions>Board options: columns, gap, sizing, rtl, responsive, binder…
widgetTypes?WidgetTypesMaps a widget kind to the React component that renders it.
activeView?stringThe visible view (the tab pattern). Omit for kit-managed.
layout?'grid' | 'split'LIVE SWITCHES — the toolbar toggles as props. Each is applied at mount (over options) and, when it changes afterwards, through the handle (setLayout / setSizing / setStatic) — no remount, like activeView. 'split' is the DevExpress splitter tree; 'grid' the cell grid.
sizing?'fit' | 'grow'
static?booleanStatic board: the viewer's mode — no drag, no resize, no handles.
onReady?(handle: DashboardHandle)The typed handle, once the board is live.
onLayoutChange?(change: { viewId: string; widgets: DashboardWidgetSpec[] })Mirrors the kit's committed gestures (drag, resize, add, remove).
className?string
style?CSSProperties
children?ReactNode

GrafloriaDiagramProps

ts
interface GrafloriaDiagramProps

Properties

NameTypeDefaultDescription
specRenderSpecAny kit spec — erDiagram(...), umlDiagram(...), dashboard(...), or DSL text.
options?RenderOptionsOptions passed through to the underlying createDiagram.
onReady?(instance: DiagramInstance)
className?string
style?CSSProperties

GrafloriaFlowProps

ts
interface GrafloriaFlowProps

Properties

NameTypeDefaultDescription
nodes?NodeSpec[]Controlled nodes. Provide with onNodesChange (see useNodesState).
edges?EdgeSpec[]Controlled edges.
groups?Array<GroupSpec | GroupModel>Controlled groups — zones around some nodes (a spec's groups, or the live GroupModels of a loaded document). Reconciled like nodes.
defaultNodes?NodeSpec[]Uncontrolled nodes — the instance owns them from here on.
defaultEdges?EdgeSpec[]
defaultGroups?Array<GroupSpec | GroupModel>
onNodesChange?(nodes: NodeModel[])
onEdgesChange?(edges: LinkModel[])
onSelectionChange?(change: { nodes: NodeModel[]; edges: LinkModel[] })
onConnect?(change: { link: LinkModel })
onNodeClick?(change: { node: NodeModel; world: { x: number; y: number } })
onEdgeClick?(change: { edge: LinkModel; world: { x: number; y: number } })
onInit?(instance: DiagramInstance)
nodeTypes?NodeTypesCustom node components, keyed by node type.
theme?Theme
fitView?boolean
enablePan?boolean
enableZoom?boolean
zoomSensitivity?number
dragThreshold?number
readonly?boolean
minZoom?number
maxZoom?number
ssr?{ html: string; snapshot: HydrationSnapshot }The renderToStaticSVG() result. Renders server-side, hydrates client-side.
layout?string | { name: string; options?: Record<string, unknown> }Declarative auto-layout — any engine registry name ('elk', 'dagre', 'force', 'tree', 'grid', 'auto', …) or { name, options }. Re-runs when the prop VALUE changes, never when node data changes.
onLayoutDone?(result: unknown)Fires after each declarative layout completes.
plugins?boolean | CanvasPluginOptionsCanvas plugins — true mounts minimap + zoom/fit controls + background grid with defaults; an object picks and configures them.
collab?GrafloriaCollabOptionsReal-time collaboration: hand in a transport (BroadcastChannelTransport, WebSocketTransport, MemoryTransport, …) and an actor id — the flow joins a CRDT sync session at mount and leaves on unmount. Fixed for the life of the instance.
onCollabReady?(session: SyncAdapter)The live SyncAdapter, right after join().
comments?boolean | CommentStoreAnchored comment threads — true creates a store, or pass a shared CommentStore. Read it back with useGrafloria()?.getCommentStore().
commentsViewer?stringViewer id for a comments: true-created store.
rendererConfig?Record<string, unknown>Renderer config passthrough (parallelLinks, parallelSpacing, jump styles, …).
interaction?Record<string, unknown>Interaction config passthrough (portVisibility, enableHelperLines, …).
tokenBridge?unknownDesign-token bridge — adopt the app's shadcn / MUI / Tailwind CSS variables.
highlighterConfig?boolean | Partial<HighlighterConfig>The outline layer Angular's canvas draws: outlines around the hovered node, the selected node, nodes with a validation issue, and valid connection targets. true turns every kind on; an object turns kinds on or off one by one. Off when unset. Live: follows the prop by value.
highlightConnected?boolean | HighlightConnectedOptionsBring the selected nodes' lines forward and fade the rest: true, or options (depth, stroke, outgoing, dimOpacity). Off when unset. Live: follows the prop by value.
className?string
style?CSSProperties
children?ReactNodeOverlays (toolbars, panels). Rendered as siblings of the canvas.

GrafloriaProviderProps

ts
interface GrafloriaProviderProps

Properties

NameTypeDefaultDescription
children?ReactNode

GrafloriaStore

The provider + the store behind useGrafloria().

React Flow's ergonomics come from exactly this shape: a <ReactFlowProvider> that lets a toolbar, a sidebar or a minimap — components that are SIBLINGS of the canvas, not children of it — reach the live instance. We keep that shape, but the thing being shared is our framework-agnostic DiagramInstance, so the provider is a 40-line store and NOT a re-implementation of the diagram.

Why a hand-rolled store rather than useSyncExternalStore: that hook is React 18+, and this package supports React 17–19. Subscribe + useState costs one extra render on attach and works everywhere.

ts
interface GrafloriaStore

Members

  • get(): DiagramInstance | null — The live instance, or null before <GrafloriaFlow> has mounted.
  • set(instance: DiagramInstance | null): void — Called by <GrafloriaFlow> on mount/unmount.
  • subscribe(listener: (instance: DiagramInstance | null) => void): () => void — Notified whenever the instance is attached or detached.

NodeProps

Props a custom node component receives. Deliberately React-Flow-shaped.

ts
interface NodeProps<TData = Record<string, unknown>>

Properties

NameTypeDefaultDescription
idstring
dataTData
selectedboolean
nodeNodeModelThe live engine model — the escape hatch.

SelectionChange

ts
interface SelectionChange

Properties

NameTypeDefaultDescription
nodesNodeModel[]
edgesLinkModel[]

WidgetProps

Props a widget component receives — the NodeProps twin for boards.

ts
interface WidgetProps<TData = Record<string, unknown>>

Properties

NameTypeDefaultDescription
widgetDashboardWidgetSpec
dataTData

Types

EdgesState

ts
type EdgesState = [
  EdgeSpec[],
  Dispatch<SetStateAction<EdgeSpec[]>>,
  (edges: LinkModel[]) => void,
];

NodesState

What useNodesState hands back — React Flow's tuple, with our types.

ts
type NodesState = [
  NodeSpec[],
  Dispatch<SetStateAction<NodeSpec[]>>,
  (nodes: NodeModel[]) => void,
];

NodeTypes

nodeTypes maps a node's type to the component that renders it.

ts
type NodeTypes = Record<string, ComponentType<NodeProps<never>>>;

WidgetTypes

ts
type WidgetTypes = Record<string, ComponentType<WidgetProps>>;

Also exported from here

These names are documented with the package that defines them, and can be imported from this one too.

  • From @grafloria/renderer: DARK_THEME, DiagramInstance, EdgeSpec, HydrationSnapshot, LIGHT_THEME, NodeSpec, PortSpec, renderToStaticSVG, StaticRenderOptions, StaticRenderResult, Theme

Was this page helpful?