Button Handle
A handle component with a button attached.
UI Component: button-handle
index.tsx
import { Position, type HandleProps } from "@xyflow/react";
import { BaseHandle } from "@/registry/components/base-handle";
const wrapperClassNames: Record<Position, string> = {
[Position.Top]:
"flex-col-reverse left-1/2 -translate-y-full -translate-x-1/2",
[Position.Bottom]: "flex-col left-1/2 translate-y-[10px] -translate-x-1/2",
[Position.Left]:
"flex-row-reverse top-1/2 -translate-x-full -translate-y-1/2",
[Position.Right]: "top-1/2 -translate-y-1/2 translate-x-[10px]",
};
export function ButtonHandle({
showButton = true,
position = Position.Bottom,
children,
...props
}: HandleProps & { showButton?: boolean }) {
const wrapperClassName = wrapperClassNames[position || Position.Bottom];
const vertical = position === Position.Top || position === Position.Bottom;
return (
<BaseHandle position={position} id={props.id} {...props}>
{showButton && (
<div
className={`absolute flex items-center ${wrapperClassName} pointer-events-none`}
>
<div
className={`bg-gray-300 ${vertical ? "h-10 w-px" : "h-px w-10"}`}
/>
<div className="nodrag nopan pointer-events-auto">{children}</div>
</div>
)}
</BaseHandle>
);
}component-example.tsx
import { Plus } from "lucide-react";
import { ConnectionState, Position, useConnection } from "@xyflow/react";
import { ButtonHandle } from "@/registry/components/button-handle";
import { BaseNode, BaseNodeContent } from "@/registry/components/base-node";
import { Button } from "@/components/ui/button";
const onClick = () => {
window.alert(`Handle button has been clicked!`);
};
const selector = (connection: ConnectionState) => {
return connection.inProgress;
};
const ButtonHandleDemo = () => {
const connectionInProgress = useConnection(selector);
return (
<BaseNode>
<BaseNodeContent>
Node with a handle button
<ButtonHandle
type="target"
position={Position.Bottom}
showButton={!connectionInProgress}
>
<Button
onClick={onClick}
size="sm"
variant="secondary"
className="rounded-full"
>
<Plus size={10} />
</Button>
</ButtonHandle>
</BaseNodeContent>
</BaseNode>
);
};
export default ButtonHandleDemo;