React Archer
React Archer is a JavaScript library for drawing dynamic, configurable SVG arrows between any DOM elements within a React application. It is currently at version 4.4.0 and maintains a consistent release cadence, with multiple feature and bugfix releases within recent months, indicating active development. Its primary utility lies in simplifying the visualization of relationships or flows between disparate UI components. Key features include customizable arrow styles (color, width, dash array, curves/angles), support for start/end markers, and the ability to update arrow positions automatically when elements move or resize. It achieves this by managing an SVG layer over your React components, dynamically calculating coordinates based on element anchors. The library supports server-side rendering and provides TypeScript types, making it robust for modern React development.
Common errors
-
Property 'refreshScreen' does not exist on type 'ArcherContainer | null'.
cause Attempting to call the `refreshScreen` method on an `ArcherContainer` ref without proper TypeScript typing or before the ref is assigned.fixEnsure your ref is correctly typed using `ArcherContainerRef` and checked for `null` before use: `const archerRef = useRef<ArcherContainerRef>(null); archerRef.current?.refreshScreen();` -
ReferenceError: document is not defined
cause `react-archer` attempting to access DOM-specific objects (like `document`) during a server-side rendering (SSR) environment before the browser's `window` or `document` objects are available.fixEnsure you are using `react-archer@4.2.2` or newer which includes SSR fixes. If issues persist, consider dynamically importing `react-archer` components only on the client-side or using a conditional rendering approach for SSR. -
Arrows are not appearing or are stuck at position (0,0).
cause This can be caused by incorrect element IDs, elements not being registered correctly, or issues with initial rendering logic within `ArcherContainer`.fixVerify that all `id` props on `ArcherElement`s are unique and valid strings. Ensure all `ArcherElement`s are descendants of an `ArcherContainer`. Update to `react-archer@4.2.0` or later for fixes related to element registration and refreshing. Check browser console for related errors.
Warnings
- breaking Version 4.0.0 completely dropped Flow type support and migrated the codebase to TypeScript. The internal implementation was also refactored to use React Hooks instead of class components.
- breaking Version 4.1.0 introduced changes to arrow ID encoding and how arrow markers are displayed, specifically by not using the full URL. This change may break arrow rendering on some older Safari browser versions, while fixing issues with URLs containing hash characters (`#`).
- gotcha Earlier versions of `react-archer` (pre-4.2.1) had known issues with Server-Side Rendering (SSR), leading to arrows not being displayed or runtime warnings.
- gotcha Prior to version 4.2.0, there were reported bugs regarding element registration and refreshing, leading to arrows not updating their positions correctly or not drawing at all.
- gotcha TypeScript users attempting to use `ref` with `ArcherContainer` components prior to v4.2.3 might have experienced improper type inference or errors.
Install
-
npm install react-archer -
yarn add react-archer -
pnpm add react-archer
Imports
- ArcherContainer
const ArcherContainer = require('react-archer').ArcherContainer;import { ArcherContainer } from 'react-archer'; - ArcherElement
import ArcherElement from 'react-archer/ArcherElement';
import { ArcherElement } from 'react-archer'; - ArcherContainerRef
import { ArcherContainerRef } from 'react-archer';import type { ArcherContainerRef } from 'react-archer';
Quickstart
import { ArcherContainer, ArcherElement } from 'react-archer';
import React from 'react';
const rootStyle = { display: 'flex', justifyContent: 'center' };
const rowStyle = { margin: '200px 0', display: 'flex', justifyContent: 'space-between' };
const boxStyle = { padding: '10px', border: '1px solid black' };
const App = () => {
return (
<div style={{ height: '500px', margin: '50px' }}>
<ArcherContainer strokeColor="red">
<div style={rootStyle}>
<ArcherElement
id="root"
relations={[
{
targetId: 'element2',
targetAnchor: 'top',
sourceAnchor: 'bottom',
style: { strokeDasharray: '5,5' }
}
]}
>
<div style={boxStyle}>Root</div>
</ArcherElement>
</div>
<div style={rowStyle}>
<ArcherElement
id="element2"
relations={[
{
targetId: 'element3',
targetAnchor: 'left',
sourceAnchor: 'right',
style: { strokeColor: 'blue', strokeWidth: 1 },
label: <div style={{ marginTop: '-20px' }}>Arrow 2</div>
}
]}
>
<div style={boxStyle}>Element 2</div>
</ArcherElement>
<ArcherElement id="element3">
<div style={boxStyle}>Element 3</div>
</ArcherElement>
<ArcherElement
id="element4"
relations={[
{
targetId: 'root',
targetAnchor: 'right',
sourceAnchor: 'left',
label: 'Arrow 3'
}
]}
>
<div style={boxStyle}>Element 4</div>
</ArcherElement>
</div>
</ArcherContainer>
</div>
);
};
export default App;