Flow
A pipeline, dependency graph or database schema on a pannable canvas: steps with a status, smooth edges, rows joined row to row, auto layout, draggable nodes saved to localStorage, a hover card and a context menu.
Presets
Looks for c2-flow. The node variables (--c2-flow__node--*) and the edge colours do most of the work; the status colours are shared by the glyphs, the edges and the node borders.
<style>
.flow-default {
width: 100%;
}
</style>
<c2-flow client:only="lit" class="flow-default" aria-label="Pipeline" nodes='[{"id":"build","label":"Build","status":"success","meta":"2m"},{"id":"test","label":"Test","status":"running"},{"id":"deploy","label":"Deploy","status":"pending"}]' edges='[{"source":"build","target":"test"},{"source":"test","target":"deploy"}]'></c2-flow><style>
.flow-compact {
width: 100%;
--c2-flow--height: 300px;
--c2-flow__node--width: 150px;
--c2-flow__node--padding-top: 6px;
--c2-flow__node--padding-bottom: 6px;
--c2-flow__node--padding-left: 10px;
--c2-flow__node--padding-right: 10px;
--c2-flow__node--border-radius: 999px;
--c2-flow__label--font-size: 12px;
--c2-flow__rank--gap: 40px;
--c2-flow__node--gap: 12px;
--c2-flow__dot--color: transparent;
}
</style>
<c2-flow client:only="lit" class="flow-compact" aria-label="Warehouse load" direction="TB" edge-type="step" nodes='[{"id":"orders","label":"Extract orders","status":"success","description":"postgres"},{"id":"customers","label":"Extract customers","status":"success","description":"crm api"},{"id":"validate","label":"Validate","status":"warning","description":"14 rows quarantined"},{"id":"transform","label":"Transform","status":"success","description":"dbt"},{"id":"load","label":"Load warehouse","status":"error","description":"No active warehouse"},{"id":"report","label":"Quality report","status":"skipped"},{"id":"dash","label":"Refresh dashboards","status":"skipped"}]' edges='[{"source":"orders","target":"validate"},{"source":"customers","target":"validate"},{"source":"validate","target":"transform"},{"source":"transform","target":"load"},{"source":"load","target":"report"},{"source":"load","target":"dash"}]'></c2-flow><style>
.flow-blueprint {
width: 100%;
--c2-flow--height: 260px;
--c2-flow--border-radius: 0;
--c2-flow__dot--gap: 12px;
--c2-flow__node--border-radius: 0;
--c2-flow__node--box-shadow: 3px 3px 0 color-mix(in srgb, var(--c2-theme--color-on-surface, #18181b) 85%, var(--c2-theme--color-surface, #ffffff));
--c2-flow__node--border: 1.5px solid var(--c2-theme--color-on-surface, #18181b);
--c2-flow__edge--width: 2px;
--c2-flow__edge__done--color: var(--c2-theme--color-on-surface, #18181b);
--c2-flow__handle--border-color: var(--c2-theme--color-on-surface, #18181b);
}
</style>
<c2-flow client:only="lit" class="flow-blueprint" aria-label="Batch with retries" nodes='[{"id":"fetch","label":"Fetch","status":"success"},{"id":"process","label":"Process batch","status":"running","description":"attempt 3"},{"id":"check","label":"Check result","status":"pending"},{"id":"publish","label":"Publish","status":"pending"}]' edges='[{"source":"fetch","target":"process"},{"source":"process","target":"check"},{"source":"check","target":"process"},{"source":"check","target":"publish"}]'></c2-flow><style>
.flow-mindmap {
width: 100%;
--c2-flow--height: 300px;
--c2-flow__node--border-radius: 999px;
--c2-flow__connector--background-color: #db2777;
--c2-flow__node__connect-target--border-color: #db2777;
--c2-flow__node__connect-target--box-shadow: 0 0 0 3px rgba(219, 39, 119, 0.2);
--c2-flow__edge__draft--color: #db2777;
--c2-flow__edge__selected--color: #db2777;
--c2-flow__editor--border-radius: 999px;
--c2-flow__editor__focus--outline: 2px solid rgba(219, 39, 119, 0.4);
}
</style>
<c2-flow client:only="lit" class="flow-mindmap" data-flow-demo="editable" editable aria-label="Mind map" nodes='[{"id":"trip","label":"Weekend trip"},{"id":"where","label":"Where?"},{"id":"budget","label":"Budget"}]' edges='[{"source":"trip","target":"where"},{"source":"trip","target":"budget"}]'></c2-flow><style>
.flow-schema {
width: 100%;
--c2-flow--height: 340px;
--c2-flow__marker--display: none;
--c2-flow__node--width: 200px;
--c2-flow__node--border-radius: 6px;
--c2-flow__rank--gap: 80px;
--c2-flow__row--min-height: 28px;
--c2-flow__row--font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
--c2-flow__row--font-size: 12px;
--c2-flow__edge--color: light-dark(#0d9488, #8cc9c4);
--c2-flow__handle--border-color: light-dark(#0d9488, #8cc9c4);
--c2-flow__row__highlighted--background-color: light-dark(#ccfbf1, #0f3b37);
}
</style>
<c2-flow client:only="lit" class="flow-schema" data-flow-demo="schema" edge-type="step" aria-label="Blog schema" nodes='[{"id":"users","label":"users","rows":[{"id":"id","label":"id","meta":"uuid"},{"id":"handle","label":"handle","meta":"text"},{"id":"joined_at","label":"joined_at","meta":"date"}]},{"id":"posts","label":"posts","rows":[{"id":"id","label":"id","meta":"uuid"},{"id":"author_id","label":"author_id","meta":"uuid"},{"id":"title","label":"title","meta":"text"},{"id":"published","label":"published","meta":"bool"}]},{"id":"comments","label":"comments","rows":[{"id":"id","label":"id","meta":"uuid"},{"id":"post_id","label":"post_id","meta":"uuid"},{"id":"author_id","label":"author_id","meta":"uuid"},{"id":"body","label":"body","meta":"text"}]}]' edges='[{"source":"users","sourcePort":"id","target":"posts","targetPort":"author_id","sourceMarker":"one","targetMarker":"many"},{"source":"posts","sourcePort":"id","target":"comments","targetPort":"post_id","sourceMarker":"one","targetMarker":"zero-many"},{"source":"users","sourcePort":"id","target":"comments","targetPort":"author_id","sourceMarker":"one","targetMarker":"zero-many"}]'></c2-flow>