Base Node

A node wrapper with some basic styling used for creating a shared design among all nodes in your application. Similarly to shadcn ui’s card the components file exports:

  • The BaseNode main container,
  • The BaseNodeHeader container where you would usually add actions and a BaseNodeHeaderTitle
  • The BaseNodeContent container where you would add the main contents of the node.
  • The BaseNodeFooter container where you may want to add extra information, or visible actions.

In case you need to fine-tune how interactions like dragging and scrolling work with your custom components, React Flow provides several CSS utility classes

You should use the nodrag React Flow utility class in interactive components of your node such as buttons, to disable dragging the node inside the flow when the user is interacting with buttons or sliders.

UI Component: base-node

index.tsx
import type { ComponentProps } from "react";
 
import { cn } from "@/lib/utils";
 
export function BaseNode({ className, ...props }: ComponentProps<"div">) {
  return (
    <div
      className={cn(
        "bg-card text-card-foreground relative rounded-md border",
        "hover:ring-1",
        // React Flow displays node elements inside of a `NodeWrapper`
        // component, which compiles down to a div with the class
        // `react-flow__node`. When a node is selected, the class `selected` is
        // added to the `react-flow__node` element. This allows us to style the
        // node when it is selected.
        "in-[.selected]:border-muted-foreground",
        "in-[.selected]:shadow-lg",
        className,
      )}
      tabIndex={0}
      {...props}
    />
  );
}
 
/**
 * A container for a consistent header layout intended to be used inside the
 * `<BaseNode />` component.
 */
export function BaseNodeHeader({
  className,
  ...props
}: ComponentProps<"header">) {
  return (
    <header
      {...props}
      className={cn(
        "mx-0 my-0 -mb-1 flex flex-row items-center justify-between gap-2 px-3 py-2",
        // Remove or modify these classes if you modify the padding in the
        // `<BaseNode />` component.
        className,
      )}
    />
  );
}
 
/**
 * The title text for the node. To maintain a native application feel, the title
 * text is not selectable.
 */
export function BaseNodeHeaderTitle({
  className,
  ...props
}: ComponentProps<"h3">) {
  return (
    <h3
      data-slot="base-node-title"
      className={cn("user-select-none flex-1 font-semibold", className)}
      {...props}
    />
  );
}
 
export function BaseNodeContent({
  className,
  ...props
}: ComponentProps<"div">) {
  return (
    <div
      data-slot="base-node-content"
      className={cn("flex flex-col gap-y-2 p-3", className)}
      {...props}
    />
  );
}
 
export function BaseNodeFooter({ className, ...props }: ComponentProps<"div">) {
  return (
    <div
      data-slot="base-node-footer"
      className={cn(
        "flex flex-col items-center gap-y-2 border-t px-3 pb-3 pt-2",
        className,
      )}
      {...props}
    />
  );
}
component-example.tsx
import { memo } from "react";
 
import { Button } from "@/components/ui/button";
import {
  BaseNode,
  BaseNodeContent,
  BaseNodeFooter,
  BaseNodeHeader,
  BaseNodeHeaderTitle,
} from "@/registry/components/base-node";
import { Rocket } from "lucide-react";
 
export const BaseNodeFullDemo = memo(() => {
  return (
    <BaseNode className="w-96">
      <BaseNodeHeader className="border-b">
        <Rocket className="size-4" />
        <BaseNodeHeaderTitle>Header</BaseNodeHeaderTitle>
      </BaseNodeHeader>
      <BaseNodeContent>
        <h3 className="text-lg font-bold">Content</h3>
        <p className="text-xs">
          This is a full-featured node with a header, content, and footer. You
          can customize it as needed.
        </p>
      </BaseNodeContent>
      <BaseNodeFooter>
        <h4 className="text-md self-start font-bold">Footer</h4>
 
        <Button variant="outline" className="nodrag w-full">
          Action 1
        </Button>
      </BaseNodeFooter>
    </BaseNode>
  );
});
 
BaseNodeFullDemo.displayName = "BaseNodeFullDemo";

Theming

To customize the visual appearance of your custom nodes, you can simply use Tailwind CSS classes. All of the React Flow components are based on shadcn UI, and you should follow the shadcn UI theming guide to customize aspects like typography and colors in your application.

In most occasions though, when developing custom nodes, you may simply need to add custom Tailwind CSS classes. All of the BaseNode components are just light wrappers around <div>.

For example, to change the border color of a node, based on an hypothetical execution status, you can pass extra classNames:

// Assuming your component is receiving a `data` prop
export const BaseNodeSimpleDemo = memo(({ data }: NodeProps) => {
  return (
    <BaseNode
      className={cn('w-[350px] p-0 hover:ring-orange-500', {
        'border-orange-500': data.status === 'loading',
        'border-red-500': data.status === 'error',
      })}
    >
      {/* Your custom node definiton goes here */}
    </BaseNode>
  );
});