Description:
CurvedArrow is a DOM-aware React component that renders animated, curved SVG arrows.
It connects two elements or coordinates with support for various curve styles, custom arrowheads, and gradient strokes.
Features
- 🎯 Flexible Positioning: Connect arrows using either element references or specific XY coordinates.
- 🌈 Customizable Curves: Choose from multiple curve styles, including
smooth,s-curve,wave, andzigzag. - 🧭 Obstacle Avoidance: Automatically reroutes arrows to avoid designated elements on the screen.
- 🖋️ Stylable Arrowheads: Customize arrowhead shapes, colors, fills, and sizes for both ends of the arrow.
- 🧩 Two-Layer Rendering: Manages z-index with
UNDERandOVERlayers for correct stacking with other UI elements. - 💫 Built-in Animations: Apply an optional motion dash overlay with configurable duration and direction.
- ⚙️ Performance Optimized: Utilizes
ResizeObserver,MutationObserver, andrequestAnimationFramefor efficient updates. - ♿ Accessibility Ready: Implements ARIA labels and roles to ensure the component is accessible.
- 🎨 Tailwind Integration: Leverages
class-variance-authorityfor easy styling with variants likeglow,neon, andfire.
Use Cases
- Diagram tools: Create flowchart and architecture diagram applications with connecting arrows.
- Tutorial systems: Guide users through interface elements with animated pointer arrows.
- Interactive UIs: Visualize relationships between components in data visualization dashboards.
- Educational content: Build interactive learning materials with connected concept maps.
How to Use It
1. Install CurvedArrow into your project with shadcn/ui CLI.
For npm:
npx shadcn@canary add https://dsa.hncore.website/r/curved-arrow.jsonFor bun:
bunx --bun shadcn@canary add https://dsa.hncore.website/r/curved-arrow.jsonFor pnpm:
pnpx shadcn@canary add https://dsa.hncore.website/r/curved-arrow.json2. Import the component into your React file.
import { CurvedArrow } from "@/components/curved-arrow";3. Connecting two DOM elements. Create ref objects using the useRef hook and assign them to the elements you want to connect. The parent container must have a relative position for the arrow to be placed correctly.
import { CurvedArrow } from "./CurvedArrow";
import { useRef } from "react";
function ElementConnector() {
const startRef = useRef(null);
const endRef = useRef(null);
return (
<div className="relative h-96 w-full border p-4">
<div ref={startRef} className="absolute top-10 left-10 z-10 w-24 h-24 bg-gray-200 flex items-center justify-center">
Start
</div>
<div ref={endRef} className="absolute bottom-10 right-10 z-10 w-24 h-24 bg-gray-200 flex items-center justify-center">
End
</div>
<CurvedArrow
startElement={startRef}
endElement={endRef}
curveType="s-curve"
variant="neon"
/>
</div>
);
}4. You can also draw an arrow between specific coordinates without attaching it to elements. Use the startX, startY, endX, and endY props to define the points. This method is useful for static diagrams or when element refs are not available.
function CoordinateConnector() {
return (
<div className="relative h-96 w-full border p-4">
<CurvedArrow
startX={50}
startY={50}
endX={300}
endY={200}
curveType="wave"
color="#3498db"
strokeWidth={5}
endArrowShape="circle"
endArrowFilled={true}
/>
</div>
);
}5. All component props.
| Prop | Type | Default | Description |
|---|---|---|---|
startElement | React.RefObject<HTMLElement> | – | Reference to the start element. Overrides startX/startY. |
endElement | React.RefObject<HTMLElement> | – | Reference to the end element. Overrides endX/endY. |
obstacleElements | React.RefObject<HTMLElement>[] | [] | Array of refs to elements for the arrow to avoid. |
startX, startY | number | 0 | Absolute start coordinates if startElement is not provided. |
endX, endY | number | 100 | Absolute end coordinates if endElement is not provided. |
startPosition | string | "center" | Docking position for startElement (e.g., top, right-center). |
endPosition | string | "center" | Docking position for endElement. |
curveIntensity | number | 0.4 | Curve strength (0 to 1+). |
curveType | string | "smooth" | Curve style (smooth, dramatic, s-curve, wave, zigzag). |
curveDirection | "up" | "down" | "left" | "right" | "auto" | "auto" | Directional bias for curves. |
strokeWidth | number | 4 | Base stroke width for the main path. |
color | string | "#852DEE" | Solid stroke color. |
gradientFrom | string | "#ffffff" | Gradient start color. |
gradientTo | string | "#852DEE" | Gradient end color. |
showStartArrow | boolean | false | Shows an arrowhead at the start. |
showEndArrow | boolean | true | Shows an arrowhead at the end. |
startArrowShape | string | "triangle" | Shape of the start arrowhead (circle, star, chevron). |
endArrowShape | string | "triangle" | Shape of the end arrowhead. |
startArrowRotation | number | 0 | Rotation for the start arrowhead in degrees. |
endArrowRotation | number | 0 | Rotation for the end arrowhead in degrees. |
startArrowSize | number | – | Size override for the start arrowhead. |
endArrowSize | number | – | Size override for the end arrowhead. |
arrowSize | number | 20 | Base size for arrowheads. |
startArrowFilled | boolean | false | Fills the start arrowhead with stroke or gradient color. |
endArrowFilled | boolean | false | Fills the end arrowhead with stroke or gradient color. |
startArrowStrokeColor | string | – | Stroke color override for the start arrowhead. |
endArrowStrokeColor | string | – | Stroke color override for the end arrowhead. |
startArrowFillColor | string | – | Fill color override for the start arrowhead. |
endArrowFillColor | string | – | Fill color override for the end arrowhead. |
startArrowStrokeWidth | number | – | Stroke width override for the start arrowhead. |
endArrowStrokeWidth | number | – | Stroke width override for the end arrowhead. |
startArrowOpacity | number | 1 | Opacity for the start arrowhead (0 to 1). |
endArrowOpacity | number | 1 | Opacity for the end arrowhead (0 to 1). |
startHeadLayer | "under" | "over" | "over" | Layer for the start arrowhead. |
endHeadLayer | "under" | "over" | "over" | Layer for the end arrowhead. |
startLineOverHead | boolean | false | Draws a line overlay over the start arrowhead. |
endLineOverHead | boolean | false | Draws a line overlay over the end arrowhead. |
animated | boolean | true | Enables the animated dash overlay. |
animationDuration | string | "2s" | Duration of one animation cycle. |
animationDelay | string | "0s" | Delay before the animation starts. |
animationDirection | "forward" | "reverse" | "alternate" | "alternate-reverse" | "forward" | Animation direction mode. |
ariaLabel | string | "Curved arrow connector" | Accessible label for the UNDER layer. |
variant | string | "default" | Tailwind style variant (glow, neon, fire). |
size | string | "default" | Stroke size variant (xs, sm, lg). |
className | string | – | Additional class names for the container. |
FAQs
Q: Does CurvedArrow work with dynamically positioned elements?
A: Yes, the component tracks element position changes using ResizeObserver and MutationObserver.
Q: How does obstacle avoidance work?
A: The component uses heuristic routing algorithms to calculate paths around specified obstacle elements.
Q: Is the component accessible to screen readers?
A: Yes, it includes ARIA labels and proper semantic structure for accessibility compliance.