excalidraw-design-guide
Excalidraw Diagram Design Guide
Color Palette
Stroke Colors (borders & text)
| Name | Hex | Use for |
|---|---|---|
| Black | #1e1e1e | Default text & borders |
| Red | #e03131 | Errors, warnings, critical |
| Green | #2f9e44 | Success, approved, healthy |
| Blue | #1971c2 | Primary actions, links |
| Purple | #9c36b5 | Services, middleware |
| Orange | #e8590c | Async, queues, events |
| Cyan | #0c8599 | Data stores, databases |
| Gray | #868e96 | Annotations, secondary |
Fill Colors (backgroundColor — pastel)
| Name | Hex | Pairs with stroke |
|---|---|---|
| Light Red | #ffc9c9 | #e03131 |
| Light Green | #b2f2bb | #2f9e44 |
| Light Blue | #a5d8ff | #1971c2 |
| Light Purple | #eebefa | #9c36b5 |
| Light Orange | #ffd8a8 | #e8590c |
| Light Cyan | #99e9f2 | #0c8599 |
| Light Gray | #e9ecef | #868e96 |
| White | #ffffff | #1e1e1e |
Sizing Rules
- Minimum shape: width >= 120px, height >= 60px
- Shape width formula:
max(160, charCount * 11 + 40)— the+40is mandatory padding, never skip it - Multi-word labels: measure the longest single word:
max(160, longestWord * 11 + 80) - Shape height: 60px single-line, 80px two-line, 100px three-line labels
- Font sizes: body text >= 16, titles/headers >= 20, small labels >= 14
- Padding: at least 20px inside shapes for text breathing room
- Arrow gap: minimum 80px between connected shapes — closer = arrows overdraw the border
- Consistent sizing: same-role shapes = same dimensions
Layout Patterns
- Grid snap: align to 20px grid for clean layouts
- Spacing: 40–80px gap between adjacent shapes
- Flow direction: top-to-bottom (vertical) or left-to-right (horizontal)
- Hierarchy: important nodes larger or higher; left-to-right = temporal order
- Grouping: cluster related elements; use background rectangles as zones
- Tier layout:
- Tier 1 (y=50–130): Client apps / entry points
- Tier 2 (y=200–280): Gateway / edge layer
- Tier 3 (y=350–440): Services (spread wide: 160–200px apart)
- Tier 4 (y=510–590): Data stores
- Side panels: x < 0 or x > mainDiagramRight + 80
Arrow Best Practices
Binding (always use element IDs, not raw coordinates)
{"type": "arrow", "x": 0, "y": 0, "start": {"id": "svc-a"}, "end": {"id": "svc-b"}}
Server auto-routes arrows to element edges using precise geometry.
Line styles
- Solid: synchronous calls, direct dependencies
- Dashed (
"strokeStyle": "dashed"): async flows, optional paths, events - Dotted (
"strokeStyle": "dotted"): weak dependencies, annotations
Arrowheads
"endArrowhead": "arrow"— default directed flow"endArrowhead": "dot"— data stores / database relationships"endArrowhead": "bar"— cardinality (ER diagrams)"endArrowhead": "triangle"— filled triangle (UML)"endArrowhead": null— plain line (undirected)"startArrowhead"mirrors the same options for bidirectional arrows
Labels on arrows
Use "label": {"text": "HTTP"} — keep to 1–2 words. Long labels overlap shapes.
Routing complex arrows (avoid crossings)
Elbowed arrow (right-angle routing — cleanest for architecture diagrams):
{
"type": "arrow", "x": 0, "y": 0,
"start": {"id": "svc-a"},
"end": {"id": "svc-b"},
"elbowed": true
}
Curved arc (for arrows that need to arc over elements):
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0,0],[50,-40],[200,0]],
"roundness": {"type": 2},
"strokeColor": "#1971c2"
}
Fill Styles (fillStyle)
Controls how shape interiors are rendered. Default is "hachure" (Excalidraw's signature sketchy look).
| Value | Appearance | Best for |
|---|---|---|
"solid" |
Flat solid color | Clean production diagrams |
"hachure" |
Diagonal hatching (default) | Sketchy/hand-drawn style |
"cross-hatch" |
Grid hatching | Emphasis, dense areas |
"dots" |
Dot pattern | Light texture, secondary elements |
"zigzag" |
Zigzag lines | Decorative, callouts |
"zigzag-line" |
Single zigzag | Borders/edges |
Use "solid" for any diagram meant to look professional. Only use "hachure" if you want the hand-drawn aesthetic intentionally.
{"type": "rectangle", "fillStyle": "solid", "backgroundColor": "#a5d8ff", ...}
Rounded Corners (roundness)
Add "roundness": {"type": 3} to rectangle and ellipse elements for rounded corners.
{"type": "rectangle", "roundness": {"type": 3}, ...}
Omit roundness (or set to null) for sharp corners.
Diagram Type Templates
Architecture Diagram
{
"elements": [
{
"id": "zone-backend",
"type": "rectangle",
"x": 40, "y": 40, "width": 600, "height": 400,
"backgroundColor": "#e9ecef", "strokeColor": "#868e96",
"opacity": 40,
"label": {"text": "Backend", "fontSize": 20}
},
{
"id": "api-gw",
"type": "rectangle",
"x": 80, "y": 100, "width": 180, "height": 70,
"strokeColor": "#9c36b5", "backgroundColor": "#eebefa",
"label": {"text": "API Gateway"}
},
{
"id": "auth-svc",
"type": "rectangle",
"x": 80, "y": 240, "width": 180, "height": 70,
"strokeColor": "#1971c2", "backgroundColor": "#a5d8ff",
"label": {"text": "Auth Service"}
},
{
"id": "db",
"type": "rectangle",
"x": 80, "y": 380, "width": 180, "height": 70,
"strokeColor": "#0c8599", "backgroundColor": "#99e9f2",
"label": {"text": "Postgres"}
},
{"type":"arrow","x":0,"y":0,"start":{"id":"api-gw"},"end":{"id":"auth-svc"},"label":{"text":"JWT verify"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"auth-svc"},"end":{"id":"db"},"label":{"text":"SQL"},"strokeStyle":"dashed"}
]
}
Flowchart
{
"elements": [
{"id":"start","type":"ellipse","x":160,"y":40,"width":120,"height":60,
"strokeColor":"#2f9e44","backgroundColor":"#b2f2bb","label":{"text":"Start"}},
{"id":"step1","type":"rectangle","x":140,"y":160,"width":160,"height":60,
"strokeColor":"#1971c2","backgroundColor":"#a5d8ff","label":{"text":"Validate Input"}},
{"id":"decide","type":"diamond","x":140,"y":280,"width":160,"height":80,
"strokeColor":"#e8590c","backgroundColor":"#ffd8a8","label":{"text":"Valid?"}},
{"id":"end-ok","type":"ellipse","x":340,"y":290,"width":100,"height":60,
"strokeColor":"#2f9e44","backgroundColor":"#b2f2bb","label":{"text":"Success"}},
{"id":"end-err","type":"ellipse","x":0,"y":290,"width":100,"height":60,
"strokeColor":"#e03131","backgroundColor":"#ffc9c9","label":{"text":"Error"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"start"},"end":{"id":"step1"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"step1"},"end":{"id":"decide"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"decide"},"end":{"id":"end-ok"},"label":{"text":"Yes"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"decide"},"end":{"id":"end-err"},"label":{"text":"No"}}
]
}
ER Diagram
{
"elements": [
{"id":"users","type":"rectangle","x":40,"y":100,"width":180,"height":120,
"strokeColor":"#1971c2","backgroundColor":"#a5d8ff",
"label":{"text":"users\n─────\nid: UUID\nname: text\nemail: text"}},
{"id":"orders","type":"rectangle","x":300,"y":100,"width":180,"height":120,
"strokeColor":"#9c36b5","backgroundColor":"#eebefa",
"label":{"text":"orders\n──────\nid: UUID\nuser_id: UUID\ntotal: decimal"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"users"},"end":{"id":"orders"},
"label":{"text":"1..N"},"endArrowhead":"arrow","startArrowhead":"dot"}
]
}
Mindmap (Clean Radial, 5 Branches)
Use this when a user asks for a minimal mindmap with directional branches.
Rules:
- Keep one center node and place first-level branches radially around it (not in a loose grid).
- Keep all labels inside shape text; never leave branch words floating outside boxes.
- Use bound arrows with
start/endIDs only. - Keep branch lengths similar unless direction intentionally emphasizes a topic.
Reference coordinates (centered canvas):
- Center:
(560, 320) - Branch vectors: up
(0,-180), right(240,-40), down-right(220,190), down-left(-220,190), left(-240,-40) - Child vectors from each branch: continue same direction by 160-220px.
Coordinate note:
- Element
x/yvalues are top-left anchors; evaluate radial balance using node centers, not top-left corners.
{
"elements": [
{"id":"center","type":"ellipse","x":560,"y":320,"width":220,"height":100,
"strokeColor":"#374151","backgroundColor":"#f3f4f6","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Focus Topic"}},
{"id":"b1","type":"rectangle","x":560,"y":140,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 1"}},
{"id":"b2","type":"rectangle","x":800,"y":280,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 2"}},
{"id":"b3","type":"rectangle","x":780,"y":510,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 3"}},
{"id":"b4","type":"rectangle","x":340,"y":510,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 4"}},
{"id":"b5","type":"rectangle","x":320,"y":280,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 5"}},
{"id":"c1","type":"rectangle","x":560,"y":-30,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 1"}},
{"id":"c2","type":"rectangle","x":1060,"y":240,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 2"}},
{"id":"c3","type":"rectangle","x":1030,"y":640,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 3"}},
{"id":"c4","type":"rectangle","x":100,"y":640,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 4"}},
{"id":"c5","type":"rectangle","x":40,"y":240,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 5"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b1"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b2"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b3"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b4"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b5"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b1"},"end":{"id":"c1"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b2"},"end":{"id":"c2"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b3"},"end":{"id":"c3"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b4"},"end":{"id":"c4"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b5"},"end":{"id":"c5"},"strokeColor":"#9ca3af","endArrowhead":"arrow"}
]
}
Anti-Patterns to Avoid
- Overlapping elements — always leave gaps; use
excalidraw distribute - Cramped spacing — minimum 40px between shapes; 60px between diagram tiers
- Tiny fonts — never below 14px; prefer 16+ for readability
- Raw arrow coordinates — always use
start/endbinding to connect to shapes - Too many colors — limit to 3–4 fill colors per diagram
- Inconsistent sizes — same-role shapes should have identical width/height
- No labels — every shape and meaningful arrow needs descriptive text
- Flat layouts — use background zones/groups to show hierarchy
- Side panels overlapping main diagram — place at x < 0 or x > mainRight + 80
- Unchecked arrow crossings — use
"elbowed": trueor route with waypoints - Forgetting
fillStyle: "solid"— default is"hachure"(sketchy); always set"fillStyle": "solid"for clean diagrams - Mindmap drift — avoid random placement; use radial vectors from center and continue each branch in the same direction
- Detached labels — if text appears outside a node, fix node label and remove loose text elements
Pre-Drawing Checklist
Before writing any JSON:
- Plan coordinate grid (tiers, x-positions, spacing)
- Calculate shape widths:
max(160, charCount * 11 + 40) - Assign IDs to all shapes that arrows will reference
- Choose 2–3 fill colors for semantic grouping
- Add
"fillStyle": "solid"to every shape for a clean look - Decide flow direction (vertical or horizontal)
- Run
excalidraw guidefor quick color/sizing reference
More from opencoredev/excalidraw-cli
excalidraw
Control a live Excalidraw canvas via the `excalidraw` CLI. Use when an agent needs to (1) draw or lay out diagrams on a live canvas, (2) create/update/delete individual elements, (3) batch-create complex diagrams from JSON, (4) inspect the canvas with describe or screenshot, (5) export/import .excalidraw files, PNG, or SVG, (6) save/restore canvas snapshots, (7) align, distribute, group, lock, or duplicate elements, (8) convert Mermaid diagrams to Excalidraw elements, (9) share diagrams as encrypted excalidraw.com URLs, and (10) execute tasks continuously through verified increments until complete. Requires a running canvas server (default http://localhost:3000).
16excalidraw-workflow
Load when building or reviewing an Excalidraw diagram. Adds an autonomous completion loop (no mid-task stops), quick planning before drawing, element-by-element build order for live progress, and a review checklist that catches overlaps, truncated text, and unconnected arrows before finishing.
10