# React Flow Documentation Visualizations Use [React Flow](https://reactflow.dev/) when structured documentation data needs an interactive spatial view: roadmaps, Gantt-like timelines, dependency graphs, or traceability maps between Features, requirements, and architectural decisions. React Flow is a renderer and interaction layer, not the authoritative data store and not a built-in layout engine. This capability assumes the local YAML data pattern in [local-yaml-data-database.md](local-yaml-data-database.md). Build nodes and edges from validated source YAML records. Never maintain a second copy of roadmap or relationship data inside TSX or MDX. ## Appropriate uses Use React Flow for: - a roadmap organized by Epic, lane, status, release, or date; - a Gantt-like roadmap where time determines horizontal position and lane determines vertical position; - Feature-to-Feature dependencies; - Requirement-to-Feature n:m traceability; - architectural decision-to-Feature n:m traceability; - a combined, filterable delivery or architecture dependency map. Do not use React Flow for ordinary prose, small static tables, or a linear list with no useful spatial relationship. Keep a semantic table fallback for every visualization so the information remains searchable, printable, and accessible without client-side JavaScript. ## Official baseline Use the current package name documented by React Flow: ```text pnpm add @xyflow/react ``` Import the required base stylesheet once in the visualization component or shared theme entry: ```ts import '@xyflow/react/dist/style.css'; ``` Relevant official guidance: - [Quick Start](https://reactflow.dev/learn) - [Layouting overview](https://reactflow.dev/learn/layouting/layouting) - [Accessibility](https://reactflow.dev/learn/advanced-use/accessibility) - [Server-side rendering](https://reactflow.dev/learn/advanced-use/ssr-ssg-configuration) - [Testing](https://reactflow.dev/learn/advanced-use/testing) React Flow does not provide one automatic graph layout. Its official layouting guide describes external options including Dagre, D3, and ELK. Choose and document the layout deliberately. ## Component boundary Keep data loading, graph adaptation, layout, and rendering separate: ```text data/**/*.yml ↓ build-time validation DocumentationDatabase ↓ pure adapter GraphModel { nodes, edges, fallbackRows, legend } ↓ pure layout PositionedGraphModel ↓ React component RoadmapFlow | DependencyMap ↓ MDX composition Documentation page ``` Recommended source structure: ```text src/components/documentation-data/ ├── react-flow/ │ ├── DocumentationFlow.tsx │ ├── RoadmapFlow.tsx │ ├── DependencyMap.tsx │ ├── nodes/ │ │ ├── FeatureNode.tsx │ │ ├── RequirementNode.tsx │ │ └── ArchitectureDecisionNode.tsx │ ├── adapters/ │ │ ├── roadmapGraph.ts │ │ ├── featureDependencyGraph.ts │ │ ├── requirementFeatureGraph.ts │ │ └── decisionFeatureGraph.ts │ ├── layout/ │ │ ├── ganttLayout.ts │ │ └── dependencyLayout.ts │ └── DocumentationFlow.module.css └── fallbacks/ ├── RoadmapTable.tsx └── TraceabilityTable.tsx ``` Adapters and layout functions must be pure TypeScript functions. Test them without a browser. React components receive already validated records or a typed graph model; they do not parse files. ## Docusaurus client boundary React Flow 12 supports server rendering when node dimensions and handle positions are supplied. That is an advanced path. For normal interactive Docusaurus documentation, use Docusaurus `BrowserOnly` to avoid hydration differences and browser-global failures: ```tsx import BrowserOnly from '@docusaurus/BrowserOnly'; import type {Props} from './DependencyMap'; export default function DependencyMapClient(props: Props) { return ( Loading dependency map…}> {() => { const DependencyMap = require('./DependencyMap').default; return ; }} ); } ``` Use `@docusaurus/BrowserOnly`, not an unguarded `window` check scattered through components. If server-rendered graph HTML is an explicit requirement, follow the official React Flow 12 SSR guidance and provide deterministic node `width` and `height`, handle positions, and initial viewport data. ## Required canvas sizing React Flow requires a parent with explicit dimensions. Never rely on content height: ```css .canvas { width: 100%; height: min(72vh, 760px); min-height: 420px; border: 1px solid var(--ifm-color-emphasis-300); border-radius: 0; } :global(.react-flow__node), :global(.react-flow__controls-button), :global(.react-flow__minimap) { border-radius: 0; } ``` Use sharp edges throughout. Do not introduce pill nodes, rounded cards, rounded controls, or rounded filter inputs. ## Shared read-only renderer Documentation views are read-only unless an editing workflow is separately approved. Disable accidental graph mutation: ```tsx import { Background, Controls, MiniMap, ReactFlow, ReactFlowProvider, type Edge, type Node, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; export function DocumentationFlow({nodes, edges}: { nodes: Node[]; edges: Edge[]; }) { return (
); } ``` Keep attribution behavior compliant with the installed package's license and React Flow terms. Do not hide attribution merely for visual preference. ## Roadmap and Gantt-like layout React Flow is not a dedicated Gantt package. Implement a Gantt-like roadmap as a deterministic node layout over validated scheduling fields. Recommended Feature source fields: ```yaml id: feature-001 title: Display project lifecycle state epic_id: epic-001 status: in-progress depends_on_feature_ids: - feature-000 roadmap: start: 2026-08-01 end: 2026-08-21 lane: portal progress: 60 ``` Layout rules: 1. Parse dates in one declared timezone and reject invalid ranges. 2. Compute `x` from `start` relative to the roadmap's minimum date. 3. Compute node width from the duration between `start` and `end`. 4. Compute `y` from the stable lane order in data or configuration. 5. Draw Feature dependency edges from `depends_on_feature_ids`. 6. Render release or milestone markers as non-connectable custom nodes. 7. Preserve a consistent time scale while zooming; include a visible date-axis component outside the graph viewport. 8. Provide filters for Epic, status, lane, release, and owner without mutating source data. 9. Provide a table fallback ordered by lane, start date, end date, and stable Feature ID. Do not let dragging persist a new schedule. A documentation reader moving a node is not a data edit. If manual positioning is required for a non-time-based roadmap, store approved coordinates in source YAML and validate them. For a roadmap without dates, use a phase or status-column layout. Keep phases in source data and calculate positions deterministically. Do not infer ordering from file enumeration. ## Dependency layouts ### Feature dependencies Build one node per Feature and one directed edge per `depends_on_feature_ids` entry. Reject missing Feature IDs. Detect cycles and either fail validation for a declared DAG or render cycles with an explicit warning when cyclic relationships are valid domain data. For ordinary directed acyclic Feature graphs, use Dagre: ```text pnpm add @dagrejs/dagre ``` Dagre is appropriate for a compact, deterministic directed layout. Set node dimensions before layout and map Dagre's center-based coordinates to React Flow positions. ### Complex or grouped dependencies For larger maps with nested Epics, compound nodes, multiple ports, or stronger edge-routing requirements, use ELK: ```text pnpm add elkjs ``` ELK layout is asynchronous. Resolve it before rendering the final graph and show a stable loading state. Do not run a new layout on every React render. ### Requirement-to-Feature traceability Create typed nodes and edges from canonical requirement `feature_ids`: ```text Functional Requirement ── satisfies/constrains ──> Feature Non-functional Requirement ── constrains ──> Feature ``` Use distinct node types, edge styles, labels, and a visible legend. Filters must distinguish functional and non-functional requirements. Do not encode meaning only with color. ### Architectural decision-to-Feature traceability Create typed nodes and edges from canonical architectural decision `feature_ids`: ```text Architectural Decision ── governs/affects ──> Feature ``` Display decision status and link each node to its canonical documentation route. A superseded decision remains traceable but must be visually and textually identified as superseded. ### Combined maps A combined map may include Features, requirements, and architectural decisions, but it must start with a constrained default scope. Large all-record graphs become unreadable and expensive. Require one or more of: - selected Epic; - selected Feature; - selected requirement type; - selected decision status; - bounded dependency depth; - search result or explicit ID list. Apply filtering before layout so hidden nodes do not consume space. ## Adapter contract A graph adapter should return all rendering and fallback information from one source: ```ts export type DocumentationGraph = { nodes: Node[]; edges: Edge[]; fallbackRows: TraceabilityRow[]; legend: LegendItem[]; warnings: GraphWarning[]; }; export function requirementFeatureGraph( database: DocumentationDatabase, filter: RequirementFeatureFilter, ): DocumentationGraph; ``` Requirements for every adapter: - stable node IDs equal stable database IDs; - stable edge IDs derived from source type, source ID, relation, and target ID; - no random coordinates or IDs; - no filesystem access; - no mutation of database records; - explicit behavior for missing, filtered, superseded, or cyclic records; - table fallback rows derived in the same function as nodes and edges. ## MDX composition MDX chooses the view and scope. It does not define nodes or edges: ```mdx --- title: "Explore Feature dependencies" description: "Inspect Feature dependencies and related requirements." --- import DependencyMapClient from '@site/src/components/documentation-data/react-flow/DependencyMapClient'; import TraceabilityTable from '@site/src/components/documentation-data/fallbacks/TraceabilityTable'; ``` The map and table must consume the same adapter output or the same normalized selector so they cannot disagree. ## Accessibility React Flow provides keyboard and screen-reader support. Preserve it: - keep `nodesFocusable` and `edgesFocusable` enabled; - keep `disableKeyboardA11y={false}`; - provide meaningful `ariaLabel` values for custom nodes and edges; - ensure custom node links and controls have visible focus states; - provide text labels in addition to colors and line styles; - provide a legend that explains node types, statuses, and edge meanings; - provide an adjacent semantic table fallback with the same filtered records; - preserve keyboard access to filters, fit-view controls, and linked detail pages; - test at 200% zoom and in both light and dark themes. Read-only means mutation is disabled, not navigation or focus. ## Performance - Memoize node types outside React components. - Build graph data with pure selectors and memoize by database revision and filter state. - Filter before layout. - Avoid recreating nodes and edges on every render. - Do not render the full database by default. - Use bounded dependency depth for large graphs. - Lazy-load the BrowserOnly visualization component. - Run asynchronous ELK layout only when the relevant graph input changes. - Measure browser interaction with representative production-size data, not only two-node examples. ## Testing and verification Test pure transformation and layout behavior first: - scheduling dates produce stable Gantt `x`, width, and lane `y` values; - Feature dependencies produce the expected directed edges; - Requirement and architectural decision n:m mappings produce complete edges; - filters remove nodes before layout; - dangling IDs fail validation before graph construction; - stable inputs produce byte-equivalent graph IDs and coordinates; - fallback table rows represent the same relationships as graph edges; - cycles follow the declared policy. Then test React behavior: - the BrowserOnly fallback renders during static generation; - the canvas mounts with explicit width and height; - nodes and edges are keyboard focusable; - graph mutation is disabled; - filters, detail links, fit view, pan, and zoom work; - missing and empty datasets render useful states; - table fallback remains usable without the graph. Required delivery checks: ```text pnpm data:validate pnpm data:check pnpm test pnpm typecheck pnpm build ``` After the production build, exercise each affected page in a real browser. Verify light and dark themes, desktop and narrow widths, keyboard navigation, labels, filters, links, pan/zoom, empty states, and the table fallback. Then verify the exact Gitea Actions SHA and deployed route. ## Acceptance checklist - [ ] `@xyflow/react` and its base stylesheet are installed and imported. - [ ] React Flow receives validated build-time data from source YAML through a pure adapter. - [ ] Roadmap scheduling and Feature dependencies are stored in YAML, not TSX or MDX. - [ ] Gantt-like positions are deterministic from dates and lanes. - [ ] Dagre or ELK is chosen explicitly for dependency layout; React Flow is not described as providing automatic layout. - [ ] Feature, requirement, and architectural decision relationships use stable IDs and typed nodes/edges. - [ ] Docusaurus uses `BrowserOnly`, or the advanced React Flow 12 SSR dimensions are fully configured. - [ ] The canvas has explicit width and height. - [ ] Documentation views disable dragging, connecting, and deletion. - [ ] Keyboard and screen-reader support remains enabled. - [ ] Sharp styling applies `border-radius: 0` to nodes, controls, minimaps, filters, and surrounding panels. - [ ] Every visualization has a semantic table fallback derived from the same adapter. - [ ] Unit, component, type, production build, browser, Actions, and deployed-route checks pass.