Canvas Draw
A versatile drawing and annotation component for images, videos, and plain canvases. Supports 9 tools, timed annotations, groups, transitions, image export, and full theme support.
Image Annotation
Use an image as the background. Draw arrows, rectangles, text, step numbers, and more to annotate screenshots, photos, or diagrams.
Annotate an Image
import { CanvasDraw } from 'fluxo-ui';
import type { DrawItem } from 'fluxo-ui';
const [items, setItems] = useState<DrawItem[]>([]);
<CanvasDraw
background={{ type: 'image', src: '/screenshot.png' }}
items={items}
onItemsChange={setItems}
style={{ height: 400 }}
/>Drawing Canvas
Use a solid color background for freeform drawing, wireframing, or whiteboard-style workflows.
Blank Canvas Drawing
<CanvasDraw
background={{ type: 'color', color: '#f8f9fa' }}
items={items}
onItemsChange={setItems}
defaultTool="freehand"
style={{ height: 350 }}
/>Toolbar Placement
Place the toolbar at any edge of the canvas. Use toolbarPlacement="none" to hide it entirely.
Bottom Toolbar
Left Toolbar
// Toolbar on the bottom
<CanvasDraw
background={{ type: 'color', color: '#eef2ff' }}
toolbarPlacement="bottom"
/>
// Vertical toolbar on the left
<CanvasDraw
background={{ type: 'color', color: '#fef3c7' }}
toolbarPlacement="left"
/>
// Available: 'top' | 'bottom' | 'left' | 'right' | 'none'Feature Flags
Use the features prop to enable or disable specific toolbar sections. By default, all features are enabled.
Minimal Toolbar — Drawing Only
<CanvasDraw
background={{ type: 'color', color: '#f0fdf4' }}
features={{
timing: false,
transitions: false,
groups: false,
export: false,
fontControls: false,
roundedCorners: false,
}}
/>Tool Subset
Use features.tools to show only specific drawing tools. Disabled tools are hidden from the toolbar.
Arrows & Rectangles Only
<CanvasDraw
background={{ type: 'color', color: '#faf5ff' }}
features={{
tools: {
select: true,
arrow: true,
rect: true,
freehand: false,
line: false,
circle: false,
text: false,
balloon: false,
step: false,
},
timing: false,
transitions: false,
groups: false,
}}
/>Timed Annotations
Each item has showAtMs, hideAtMs, and transition properties. When used with video or media, items appear and disappear at the correct timestamps with animated transitions (fade, scale, slide-*).
Timed Items — Enable Timing in Features
const items: DrawItem[] = [
{
id: 'item-1',
object: { type: 'rect', /* ... */ },
showAtMs: 0,
hideAtMs: 3000,
transition: 'fade',
groupId: null,
xPct: 0.1, yPct: 0.15, wPct: 0.3, hPct: 0.3,
},
{
id: 'item-2',
object: { type: 'arrow', /* ... */ },
showAtMs: 2000,
hideAtMs: 5000,
transition: 'scale',
groupId: null,
xPct: 0.5, yPct: 0.2, wPct: 0.3, hPct: 0.3,
},
];
<CanvasDraw
background={{ type: 'color', color: '#1a1a2e' }}
items={items}
currentMs={currentMs}
mediaDurationMs={8000}
features={{ timing: true, transitions: true, groups: true }}
/>Media Timeline
The MediaTimeline companion component provides a video-editor-style timeline view. Items appear as draggable/resizable bars. Groups are shown with colored lanes.
Interactive Timeline
import { MediaTimeline } from 'fluxo-ui';
import type { TimelineItem, TimelineGroup } from 'fluxo-ui';
const [items, setItems] = useState<TimelineItem[]>([
{ id: '1', label: 'Intro', showAtMs: 0, hideAtMs: 3000,
groupId: null, transition: 'fade' },
]);
const [groups, setGroups] = useState<TimelineGroup[]>([]);
const [selected, setSelected] = useState<string | null>(null);
const [currentMs, setCurrentMs] = useState(0);
<MediaTimeline
items={items}
groups={groups}
durationMs={10000}
currentMs={currentMs}
selectedItemId={selected}
onSelectItem={setSelected}
onUpdateItem={(id, patch) =>
setItems(prev => prev.map(it => it.id === id ? { ...it, ...patch } : it))
}
onUpdateGroup={(id, patch) =>
setGroups(prev => prev.map(g => g.id === id ? { ...g, ...patch } : g))
}
onAddGroup={() => setGroups(prev => [...prev, { id: `g-${Date.now()}`, label: 'New Group', showAtMs: 0, hideAtMs: null, transition: 'none' }])}
onDeleteGroup={(id) => setGroups(prev => prev.filter(g => g.id !== id))}
onSeek={setCurrentMs}
/>Controlled Mode
Pass items and onItemsChange to fully control the drawing state externally. Without items, the component manages its own internal state.
Controlled — Item Count Tracked Externally
const [items, setItems] = useState<DrawItem[]>([]);
<CanvasDraw
background={{ type: 'color', color: '#fff7ed' }}
items={items}
onItemsChange={setItems}
/>
// Uncontrolled — just omit items prop:
<CanvasDraw background={{ type: 'color', color: '#fff' }} />Read-Only Mode
Set isEditing={false} to hide the toolbar and disable all interactions. Useful for playback/preview mode.
View-Only with Pre-drawn Items
<CanvasDraw
background={{ type: 'image', src: '/screenshot.png' }}
items={savedItems}
isEditing={false}
/>Export
Pass onExport to enable export buttons. SVG export works out of the box. PNG/JPG/WebP require the optional html2canvas package — if not installed, export gracefully logs a message and the component continues to work.
Export Drawing
const handleExport = (dataUrl: string, format: ImageExportFormat) => {
// dataUrl contains the image data
// SVG export works without extra dependencies
// PNG/JPG/WebP requires: npm install html2canvas
console.log(`Exported ${format}:`, dataUrl.length, 'chars');
};
<CanvasDraw
background={{ type: 'color', color: '#f0f9ff' }}
onExport={handleExport}
features={{ export: true }}
/>Import
import { CanvasDraw, CanvasDrawOverlay, CanvasDrawToolbar, MediaTimeline } from 'fluxo-ui';
// Type imports
import type {
CanvasDrawProps,
CanvasDrawOverlayHandle,
CanvasDrawToolbarProps,
MediaTimelineProps,
TimelineItem,
TimelineGroup,
DrawItem,
DrawGroup,
DrawTool,
DrawColor,
DrawObject,
DrawToolDefaults,
DrawTransition,
CanvasBackground,
CanvasDrawFeatures,
ToolConfig,
ImageExportFormat,
} from 'fluxo-ui';
// Utilities
import { colorMap, defaultToolDefaults, contrastColor, autoFontColor } from 'fluxo-ui';CanvasDraw Props
backgroundreqCanvasBackgroundBackground configuration — image, color, or video reference
backgroundreqCanvasBackgroundBackground configuration — image, color, or video reference
itemsDrawItem[]Controlled items array. When provided, component is controlled
itemsDrawItem[]Controlled items array. When provided, component is controlled
groupsDrawGroup[]Controlled groups array for annotation grouping
groupsDrawGroup[]Controlled groups array for annotation grouping
currentMsnumber"0"Current playback position in milliseconds (for timed annotations)
currentMsnumber"0"Current playback position in milliseconds (for timed annotations)
mediaDurationMsnumber"0"Total media duration in milliseconds
mediaDurationMsnumber"0"Total media duration in milliseconds
isEditingboolean"true"Whether the canvas is in edit mode (shows toolbar, allows drawing)
isEditingboolean"true"Whether the canvas is in edit mode (shows toolbar, allows drawing)
toolbarPlacement'top' | 'bottom' | 'left' | 'right' | 'none'"'top'"Position of the drawing toolbar relative to the canvas
toolbarPlacement'top' | 'bottom' | 'left' | 'right' | 'none'"'top'"Position of the drawing toolbar relative to the canvas
defaultToolDrawTool"'select'"Initially active tool when the component mounts
defaultToolDrawTool"'select'"Initially active tool when the component mounts
defaultToolDefaultsPartial<DrawToolDefaults>Override default stroke color, fill, font settings, etc.
defaultToolDefaultsPartial<DrawToolDefaults>Override default stroke color, fill, font settings, etc.
featuresCanvasDrawFeatures"{}"Feature flags to enable/disable toolbar sections and tools
featuresCanvasDrawFeatures"{}"Feature flags to enable/disable toolbar sections and tools
classNamestringAdditional CSS class for the root element
classNamestringAdditional CSS class for the root element
styleReact.CSSPropertiesInline styles for the root element
styleReact.CSSPropertiesInline styles for the root element
onItemsChange(items: DrawItem[]) => voidFires whenever items are added, modified, or removed
onItemsChange(items: DrawItem[]) => voidFires whenever items are added, modified, or removed
onExport(dataUrl: string, format: ImageExportFormat) => voidCalled when user exports. Enables export buttons when provided
onExport(dataUrl: string, format: ImageExportFormat) => voidCalled when user exports. Enables export buttons when provided
DrawItem Properties
idreqstringUnique identifier for the item
idreqstringUnique identifier for the item
objectreqDrawObjectThe drawing object (arrow, rect, circle, text, etc.)
objectreqDrawObjectThe drawing object (arrow, rect, circle, text, etc.)
showAtMsreqnumberTime in ms when this item should appear
showAtMsreqnumberTime in ms when this item should appear
hideAtMsreqnumber | nullTime in ms when this item should hide (null = never)
hideAtMsreqnumber | nullTime in ms when this item should hide (null = never)
transitionreqDrawTransitionAnimation transition for show/hide (none, fade, scale, slide-*)
transitionreqDrawTransitionAnimation transition for show/hide (none, fade, scale, slide-*)
groupIdreqstring | nullOptional group membership for batch timing
groupIdreqstring | nullOptional group membership for batch timing
xPctreqnumberHorizontal position as fraction (0-1) of canvas width
xPctreqnumberHorizontal position as fraction (0-1) of canvas width
yPctreqnumberVertical position as fraction (0-1) of canvas height
yPctreqnumberVertical position as fraction (0-1) of canvas height
wPctreqnumber | nullWidth as fraction (0-1). Null for point-based items (steps)
wPctreqnumber | nullWidth as fraction (0-1). Null for point-based items (steps)
hPctreqnumber | nullHeight as fraction (0-1). Null for point-based items (steps)
hPctreqnumber | nullHeight as fraction (0-1). Null for point-based items (steps)
CanvasDrawFeatures
toolsToolConfigEnable/disable individual tools (select, arrow, rect, circle, etc.)
toolsToolConfigEnable/disable individual tools (select, arrow, rect, circle, etc.)
timingbooleanShow timing controls (showAt / hideAt) in toolbar
timingbooleanShow timing controls (showAt / hideAt) in toolbar
groupsbooleanShow group management in toolbar
groupsbooleanShow group management in toolbar
transitionsbooleanShow transition selector in toolbar
transitionsbooleanShow transition selector in toolbar
undobooleanShow undo/redo buttons
undobooleanShow undo/redo buttons
exportbooleanShow export buttons (also requires onExport prop)
exportbooleanShow export buttons (also requires onExport prop)
clearAllbooleanShow clear all button
clearAllbooleanShow clear all button
strokeColorbooleanShow stroke color picker
strokeColorbooleanShow stroke color picker
strokeWidthbooleanShow stroke width control
strokeWidthbooleanShow stroke width control
fillColorbooleanShow fill color picker
fillColorbooleanShow fill color picker
fontControlsbooleanShow font family, size, color, bold/italic/underline
fontControlsbooleanShow font family, size, color, bold/italic/underline
roundedCornersbooleanShow rounded corners toggle for rectangles
roundedCornersbooleanShow rounded corners toggle for rectangles
MediaTimeline Props
itemsreqTimelineItem[]Timeline items to display as bars
itemsreqTimelineItem[]Timeline items to display as bars
groupsreqTimelineGroup[]Timeline groups for organizing items
groupsreqTimelineGroup[]Timeline groups for organizing items
durationMsreqnumberTotal duration of the media in milliseconds
durationMsreqnumberTotal duration of the media in milliseconds
currentMsreqnumberCurrent playback position in milliseconds
currentMsreqnumberCurrent playback position in milliseconds
selectedItemIdreqstring | nullCurrently selected item ID
selectedItemIdreqstring | nullCurrently selected item ID
tickCountnumber"10"Number of time ticks to display
tickCountnumber"10"Number of time ticks to display
defaultItemColorstringDefault color for items without a group color
defaultItemColorstringDefault color for items without a group color
onSelectItemreq(id: string | null) => voidCalled when an item is selected or deselected
onSelectItemreq(id: string | null) => voidCalled when an item is selected or deselected
onUpdateItemreq(id: string, patch: Partial<TimelineItem>) => voidCalled when an item is dragged/resized on the timeline
onUpdateItemreq(id: string, patch: Partial<TimelineItem>) => voidCalled when an item is dragged/resized on the timeline
onUpdateGroupreq(id: string, patch: Partial<TimelineGroup>) => voidCalled when a group is modified
onUpdateGroupreq(id: string, patch: Partial<TimelineGroup>) => voidCalled when a group is modified
onAddGroupreq() => voidCalled when the add group button is clicked
onAddGroupreq() => voidCalled when the add group button is clicked
onDeleteGroupreq(id: string) => voidCalled when a group is deleted
onDeleteGroupreq(id: string) => voidCalled when a group is deleted
onSeekreq(ms: number) => voidCalled when the user clicks on the timeline to seek
onSeekreq(ms: number) => voidCalled when the user clicks on the timeline to seek
Features
Drawing Tools
9 built-in tools: select, arrow, line, rectangle, circle, freehand, text, balloon, step numbers
Multi-Background
Support for image, video, and solid color backgrounds
Percentage Coords
Resolution-independent positioning using 0-1 fractions
Undo / Redo
Full undo/redo stack with snapshot-on-first-change batching
Timed Annotations
Show/hide items at specific timestamps with animated transitions
Groups
Group items for batch timing and transition control
Image Export
Export as PNG, JPG, WebP, or SVG. Raster export via optional html2canvas
Toolbar Placement
4 placement options: top, bottom, left, right — plus hidden mode
Feature Flags
Granular control over which tools and toolbar sections are visible
Controlled & Uncontrolled
Works with or without external state — pass items for controlled mode
Theming
Full dark/light mode support via CSS custom properties
Media Timeline
Companion timeline component for video editing workflows