Node

Compound card for node-based editors – typed ports, composable body, and themeable port colours via CSS variables.

Install

npx shadcn@latest add https://substrate.georgedrury.co.uk/r/node

Examples

Default

Three node types demonstrating the component anatomy: a filter node with controls, a generator node with colour and dimensions, and an output node with a preview area.

Gaussian blurFilter
Image
Radius
px
Output
Solid fillGenerate
W
H
Image
Colour
Output
Final
Preview
"use client"

import { useState } from "react"

Port types

Each port type maps to a CSS variable that consumers can override to match their brand.

number
colour
image
geometry
text
boolean
any
"use client"

import {

Port type system

Ports are typed. Each type has a corresponding CSS variable for its colour:

TypeCSS variableDefault
number--node-port-numberBlue
colour--node-port-colourPink
image--node-port-imagePurple
geometry--node-port-geometryGreen
text--node-port-textAmber
boolean--node-port-booleanOrange
any--node-port-anyGrey

Override any of these in your globals.css to change port colours globally.

Node chrome variables

VariableTailwind classFallbackDescription
--node-bgbg-node-bg--cardCard background
--node-borderborder-node-border--borderCard border
--node-headerbg-node-header--mutedHeader background
--node-selectedring-node-selected--ringSelection ring colour

Components

ComponentDescription
NodeCardOuter card with border, shadow, and selected ring
NodeHeaderTitle bar with optional custom colour background
NodeTitleTruncated title text
NodeBadgeSmall type/category badge in the header
NodeBodyContent area for controls (compose Action, NumberSlider, etc.)
NodePortsVertical list of input/output ports
NodePortA single typed port with dot, label, and direction
NodePortDotColoured dot indicator (filled when connected, hollow when not)
NodePreviewOptional image/canvas preview area
NodeDividerHorizontal separator between sections

Composing node bodies

The body of a node uses the same components you'd use in a panel pane. ActionControls automatically adapts nested components:

<NodeBody>
	<Action>
		<ActionLabel>Radius</ActionLabel>
		<ActionControls>
			<NumberSlider
				value={blur}
				onChange={setBlur}
				min={0}
				max={50}
				suffix="px"
			/>
		</ActionControls>
	</Action>
</NodeBody>