diff --git a/workspace/src/app/store/ducks/error/errorSlice.ts b/workspace/src/app/store/ducks/error/errorSlice.ts
index a858365e6f..5dc7d5c73e 100644
--- a/workspace/src/app/store/ducks/error/errorSlice.ts
+++ b/workspace/src/app/store/ducks/error/errorSlice.ts
@@ -7,7 +7,7 @@ type RegisterErrorActionType = {
         /** The error that should be displayed. */
         newError: Pick<DIErrorFormat, "id" | "message" | "cause" | "alternativeIntent">;
         /** An optional error notification instance ID when this error should only be shown in a specific error notification widget. */
-        errorNotificationInstanceId?: string
+        errorNotificationInstanceId?: string;
     };
 };
 
diff --git a/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx b/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx
index 266becb74a..e698769339 100644
--- a/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx
+++ b/workspace/src/app/views/layout/Header/KeyboardShortcutsModal.tsx
@@ -57,6 +57,8 @@ const shortcuts: Record<typeof sectionKeys[number], Array<{ key: string; command
         },
         { key: "delete", commands: ["backspace"] },
         { key: "multiselect", commands: ["shift+mouse select"] },
+        { key: "copySelectedNodes", commands: ["ctrl+c", "cmd+c"] },
+        { key: "pasteNodes", commands: ["ctrl+v", "cmd+v"] },
     ],
     "workflow-editor": [
         { key: "delete", commands: ["backspace"] },
diff --git a/workspace/src/app/views/shared/RuleEditor/RuleEditor.tsx b/workspace/src/app/views/shared/RuleEditor/RuleEditor.tsx
index 301f29b583..dd6c89ebfa 100644
--- a/workspace/src/app/views/shared/RuleEditor/RuleEditor.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/RuleEditor.tsx
@@ -19,8 +19,8 @@ import utils from "./RuleEditor.utils";
 import { IStickyNote } from "views/taskViews/shared/task.typings";
 import { DatasetCharacteristics } from "../typings";
 import { ReactFlowHotkeyContext } from "@eccenca/gui-elements/src/cmem/react-flow/extensions/ReactFlowHotkeyContext";
-import {Notification} from "@eccenca/gui-elements"
-import {diErrorMessage} from "@ducks/error/typings";
+import { Notification } from "@eccenca/gui-elements";
+import { diErrorMessage } from "@ducks/error/typings";
 
 /** Function to fetch the rule operator spec. */
 export type RuleOperatorFetchFnType = (
diff --git a/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorModelContext.ts b/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorModelContext.ts
index ffdb5ec796..c0ddc1acf0 100644
--- a/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorModelContext.ts
+++ b/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorModelContext.ts
@@ -28,6 +28,8 @@ export interface RuleEditorModelContextProps {
     saveRule: () => Promise<boolean> | boolean;
     /** If there are unsaved changes. */
     unsavedChanges: boolean;
+    /** Number of selected nodes copied */
+    copiedNodesCount: number;
     /** Executes an operation that will change the model. */
     executeModelEditOperation: IModelActions;
     /** Undo last changes. Return true if changes have been undone. */
@@ -47,6 +49,7 @@ export interface RuleEditorModelContextProps {
     ruleOperatorNodes: () => IRuleOperatorNode[];
     /** The ID of the rule editor canvas element. */
     canvasId: string;
+    updateSelectedElements: (elements: Elements | null) => void;
 }
 
 export interface IModelActions {
@@ -86,6 +89,8 @@ export interface IModelActions {
     deleteEdges: (edgeIds: string[]) => void;
     /** Copy and paste a selection of nodes. Move pasted selection by the defined offset. */
     copyAndPasteNodes: (nodeIds: string[], offset?: XYPosition) => void;
+    /** Just copy a selection of nodes. */
+    copyNodes: (nodeIds: string[], offset?: XYPosition) => void;
     /** Move a single node to a new position. */
     moveNode: (nodeId: string, newPosition: XYPosition) => void;
     /** changes the size of a node to the given new dimensions */
@@ -129,6 +134,8 @@ export const RuleEditorModelContext = React.createContext<RuleEditorModelContext
         return false;
     },
     unsavedChanges: false,
+    copiedNodesCount: 0,
+    updateSelectedElements: () => {},
     executeModelEditOperation: {
         startChangeTransaction: NOP,
         addStickyNode: NOP,
@@ -146,6 +153,7 @@ export const RuleEditorModelContext = React.createContext<RuleEditorModelContext
         deleteEdges: NOP,
         changeSize: NOP,
         fixNodeInputs: NOP,
+        copyNodes: NOP,
         changeStickyNodeProperties: NOP,
     },
     undo: () => false,
diff --git a/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorUiContext.tsx b/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorUiContext.tsx
index 091332be6d..2070ba5597 100644
--- a/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorUiContext.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/contexts/RuleEditorUiContext.tsx
@@ -1,5 +1,5 @@
 import React from "react";
-import { OnLoadParams } from "react-flow-renderer";
+import { Elements, OnLoadParams } from "react-flow-renderer";
 
 /** Context for all UI related properties. */
 export interface RuleEditorUiContextProps {
@@ -26,6 +26,8 @@ export interface RuleEditorUiContextProps {
     hideMinimap?: boolean;
     /** Defines minimun and maximum of the available zoom levels */
     zoomRange?: [number, number];
+    onSelection: (elements: Elements | null) => void;
+    selectionState: { elements: Elements | null };
 }
 
 export const RuleEditorUiContext = React.createContext<RuleEditorUiContextProps>({
@@ -41,4 +43,6 @@ export const RuleEditorUiContext = React.createContext<RuleEditorUiContextProps>
     showRuleOnly: false,
     hideMinimap: false,
     zoomRange: [0.25, 1.5],
+    onSelection: () => {},
+    selectionState: { elements: null },
 });
diff --git a/workspace/src/app/views/shared/RuleEditor/model/RuleEditorModel.tsx b/workspace/src/app/views/shared/RuleEditor/model/RuleEditorModel.tsx
index be414020e9..a6ffd339d3 100644
--- a/workspace/src/app/views/shared/RuleEditor/model/RuleEditorModel.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/model/RuleEditorModel.tsx
@@ -50,6 +50,8 @@ import StickyMenuButton from "../view/components/StickyMenuButton";
 import { LanguageFilterProps } from "../view/ruleNode/PathInputOperator";
 import { requestRuleOperatorPluginDetails } from "@ducks/common/requests";
 import useErrorHandler from "../../../../hooks/useErrorHandler";
+import { PUBLIC_URL } from "../../../../constants/path";
+import { copyToClipboard } from "../../../../utils/copyToClipboard";
 
 type NodeDimensions = NodeContentProps<any>["nodeDimensions"];
 
@@ -122,10 +124,41 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
     const [utils] = React.useState(ruleEditorModelUtilsFactory());
     /** ID of the rule editor canvas. This is needed for the auto-layout operation. */
     const canvasId = `ruleEditor-react-flow-canvas-${ruleEditorContext.instanceId}`;
+    /** when a node is clicked the selected nodes appears here */
+    const [selectedElements, updateSelectedElements] = React.useState<Elements | null>(null);
+    const [copiedNodesCount, setCopiedNodesCount] = React.useState<number>(0);
 
     /** react-flow related functions */
     const { setCenter } = useZoomPanHelper();
 
+    React.useEffect(() => {
+        if (copiedNodesCount) {
+            setTimeout(() => {
+                setCopiedNodesCount(0);
+            }, 3000);
+        }
+    }, [copiedNodesCount]);
+
+    React.useEffect(() => {
+        const handlePaste = async (e) => await pasteNodes(e);
+        const handleCopy = async (e) => {
+            if (selectedElements) {
+                await copyNodes(
+                    selectedElements.map((n) => n.id),
+                    e
+                );
+                e.preventDefault();
+            }
+        };
+        window.addEventListener("paste", handlePaste);
+        window.addEventListener("copy", handleCopy);
+
+        return () => {
+            window.removeEventListener("paste", handlePaste);
+            window.removeEventListener("copy", handleCopy);
+        };
+    }, [nodeParameters, ruleEditorContext.operatorList, selectedElements]);
+
     const edgeType = (ruleOperatorNode?: IRuleOperatorNode) => {
         if (ruleOperatorNode) {
             switch (ruleOperatorNode.pluginType) {
@@ -485,6 +518,7 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
     const addOrMergeRuleModelChange = (ruleModelChanges: RuleModelChanges) => {
         const lastChange = asChangeNodeParameter(ruleUndoStack[ruleUndoStack.length - 1]);
         const parameterChange = asChangeNodeParameter(ruleModelChanges);
+
         if (
             parameterChange &&
             lastChange &&
@@ -495,6 +529,7 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
             ruleUndoStack.push(ruleModelChanges);
         } else {
             ruleUndoStack.push(ruleModelChanges);
+            console.log("Rule undo stack ==>", ruleUndoStack);
         }
     };
 
@@ -1219,6 +1254,130 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
         }, true);
     };
 
+    const pasteNodes = async (e: any) => {
+        try {
+            const clipboardData = e.clipboardData?.getData("Text");
+            const pasteInfo = JSON.parse(clipboardData); // Parse JSON
+            if (pasteInfo.task) {
+                changeElementsInternal((els) => {
+                    const nodes = pasteInfo.task.data.nodes ?? [];
+                    const nodeIdMap = new Map<string, string>();
+                    const newNodes: RuleEditorNode[] = [];
+                    nodes.forEach((node) => {
+                        const position = { x: node.position.x + 100, y: node.position.y + 100 };
+                        const op = fetchRuleOperatorByPluginId(node.pluginId, node.pluginType);
+                        if (!op) throw new Error(`Missing plugins for operator plugin ${node.pluginId}`);
+                        const newNode = createNodeInternal(
+                            op,
+                            position,
+                            Object.fromEntries(nodeParameters.get(node.id) ?? new Map())
+                        );
+                        if (newNode) {
+                            nodeIdMap.set(node.id, newNode.id);
+                            newNodes.push({
+                                ...newNode,
+                                data: {
+                                    ...newNode.data,
+                                    introductionTime: {
+                                        run: 1800,
+                                        delay: 300,
+                                    },
+                                },
+                            });
+                        }
+                    });
+                    const newEdges: Edge[] = [];
+                    pasteInfo.task.data.edges.forEach((edge) => {
+                        if (nodeIdMap.has(edge.source) && nodeIdMap.has(edge.target)) {
+                            const newEdge = utils.createEdge(
+                                nodeIdMap.get(edge.source)!!,
+                                nodeIdMap.get(edge.target)!!,
+                                edge.targetHandle!!,
+                                edge.type ?? "step"
+                            );
+                            newEdges.push(newEdge);
+                        }
+                    });
+                    startChangeTransaction();
+                    const withNodes = addAndExecuteRuleModelChangeInternal(
+                        RuleModelChangesFactory.addNodes(newNodes),
+                        els
+                    );
+                    resetSelectedElements();
+                    setTimeout(() => {
+                        unsetUserSelection();
+                        setSelectedElements([...newNodes, ...newEdges]);
+                    }, 100);
+                    return addAndExecuteRuleModelChangeInternal(RuleModelChangesFactory.addEdges(newEdges), withNodes);
+                });
+            }
+        } catch (err) {
+            //todo handle errors
+            const unExpectedTokenError = /Unexpected token/.exec(err?.message ?? "");
+            if (unExpectedTokenError) {
+                //that is, not the expected json format that contains nodes
+                registerError("RuleEditorModel.pasteCopiedNodes", "No operator has been found in the pasted data", err);
+            } else {
+                registerError("RuleEditorModel.pasteCopiedNodes", err?.message, err);
+            }
+        }
+    };
+
+    const copyNodes = async (nodeIds: string[], event?: any) => {
+        //Get nodes and related edges
+        const nodeIdMap = new Map<string, string>(nodeIds.map((id) => [id, id]));
+        const edges: Partial<Edge>[] = [];
+
+        const originalNodes = utils.nodesById(elements, nodeIds);
+        const nodes = originalNodes.map((node) => {
+            const ruleOperatorNode = node.data.businessData.originalRuleOperatorNode;
+            return {
+                id: node.id,
+                pluginId: ruleOperatorNode.pluginId,
+                pluginType: ruleOperatorNode.pluginType,
+                position: node.position,
+            };
+        });
+
+        elements.forEach((elem) => {
+            if (utils.isEdge(elem)) {
+                const edge = utils.asEdge(elem)!!;
+                if (nodeIdMap.has(edge.source) && nodeIdMap.has(edge.target)) {
+                    //edges worthy of copying
+                    edges.push({
+                        source: edge.source,
+                        target: edge.target,
+                        targetHandle: edge.targetHandle,
+                        type: edge.type ?? "step",
+                    });
+                }
+            }
+        });
+        //paste to clipboard.
+        const { projectId, editedItemId, editedItem } = ruleEditorContext;
+        const taskType = (editedItem as { type: string })?.type === "linking" ? "linking" : "transform";
+        const data = JSON.stringify({
+            task: {
+                data: {
+                    nodes,
+                    edges,
+                },
+                metaData: {
+                    domain: PUBLIC_URL,
+                    project: projectId,
+                    task: editedItemId,
+                },
+            },
+        });
+        if (event) {
+            event.clipboardData.setData("text/plain", data);
+            event.preventDefault();
+        } else {
+            copyToClipboard(data);
+        }
+        setCopiedNodesCount(nodes.length);
+    };
+
     /** Copy and paste nodes with a given offset. */
     const copyAndPasteNodes = (nodeIds: string[], offset: XYPosition = { x: 100, y: 100 }) => {
         changeElementsInternal((els) => {
@@ -1762,6 +1921,8 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
                 redo,
                 canRedo,
                 canvasId,
+                updateSelectedElements,
+                copiedNodesCount,
                 executeModelEditOperation: {
                     startChangeTransaction,
                     addNode,
@@ -1780,6 +1941,7 @@ export const RuleEditorModel = ({ children }: RuleEditorModelProps) => {
                     deleteEdges,
                     moveNodes,
                     fixNodeInputs,
+                    copyNodes,
                 },
                 unsavedChanges: canUndo,
                 isValidEdge,
diff --git a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorCanvas.tsx b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorCanvas.tsx
index b97d182d20..aeac620e1f 100644
--- a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorCanvas.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorCanvas.tsx
@@ -439,6 +439,9 @@ export const RuleEditorCanvas = () => {
                 cloneSelection={() => {
                     cloneNodes(nodeIds);
                 }}
+                copySelection={() => {
+                    modelContext.executeModelEditOperation.copyNodes(nodeIds);
+                }}
             />
         );
     };
@@ -454,6 +457,8 @@ export const RuleEditorCanvas = () => {
     // Track current selection
     const onSelectionChange = (elements: Elements | null) => {
         selectionState.elements = elements;
+        ruleEditorUiContext.onSelection(elements);
+        modelContext.updateSelectedElements(elements);
     };
 
     // Triggered after the react-flow instance has been loaded
diff --git a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorToolbar.tsx b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorToolbar.tsx
index 0786e6466b..446878733a 100644
--- a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorToolbar.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorToolbar.tsx
@@ -21,7 +21,7 @@ import { RuleEditorEvaluationContext, RuleEditorEvaluationContextProps } from ".
 import { EvaluationActivityControl } from "./evaluation/EvaluationActivityControl";
 import { Prompt } from "react-router";
 import { RuleValidationError } from "../RuleEditor.typings";
-import { DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH } from "../model/RuleEditorModel.utils";
+import utils, { DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH } from "../model/RuleEditorModel.utils";
 import { RuleEditorBaseModal } from "./components/RuleEditorBaseModal";
 import { ReactFlowHotkeyContext } from "@eccenca/gui-elements/src/cmem/react-flow/extensions/ReactFlowHotkeyContext";
 
@@ -138,6 +138,8 @@ export const RuleEditorToolbar = () => {
         }
     };
 
+    const numberOfCopiedNodes = modelContext.copiedNodesCount;
+
     return (
         <>
             {ruleEditorContext.editorTitle ? (
@@ -218,6 +220,21 @@ export const RuleEditorToolbar = () => {
                 <ToolbarSection canGrow>
                     <Spacing vertical size={"small"} />
                 </ToolbarSection>
+                {numberOfCopiedNodes ? (
+                    <>
+                        <Icon
+                            name="item-copy"
+                            tooltipText={t("RuleEditor.toolbar.copiedNotificationText", {
+                                numberOfNodes: `${numberOfCopiedNodes} node${numberOfCopiedNodes > 1 ? "s" : ""}`,
+                            })}
+                            tooltipProps={{
+                                isOpen: true,
+                                placement: "left",
+                            }}
+                        />
+                        <Spacing vertical size={"small"} />
+                    </>
+                ) : null}
                 {ruleEditorContext.additionalToolBarComponents ? ruleEditorContext.additionalToolBarComponents() : null}
                 {ruleEvaluationContext.evaluationResultsShown || ruleEvaluationContext.supportsEvaluation ? (
                     <ToolbarSection>
diff --git a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorView.tsx b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorView.tsx
index 5fd509c3ec..ef097efd00 100644
--- a/workspace/src/app/views/shared/RuleEditor/view/RuleEditorView.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/view/RuleEditorView.tsx
@@ -4,7 +4,7 @@ import { RuleEditorOperatorSidebar } from "./sidebar/RuleEditorOperatorSidebar";
 import React from "react";
 import { RuleEditorCanvas } from "./RuleEditorCanvas";
 import { RuleEditorUiContext } from "../contexts/RuleEditorUiContext";
-import { OnLoadParams } from "react-flow-renderer";
+import { Elements, OnLoadParams } from "react-flow-renderer";
 
 interface RuleEditorViewProps {
     /** When enabled only the rule is shown without side- and toolbar and any other means to edit the rule. */
@@ -24,6 +24,12 @@ export const RuleEditorView = ({ showRuleOnly, hideMinimap, zoomRange, readOnlyM
     const [currentRuleNodeDescription, setCurrentRuleNodeDescription] = React.useState<string | undefined>("");
     const reactFlowWrapper = React.useRef<any>(null);
     const [reactFlowInstance, setReactFlowInstance] = React.useState<OnLoadParams | undefined>(undefined);
+    // At the moment react-flow's selection logic is buggy in some places, e.g. https://github.com/wbkd/react-flow/issues/1314
+    // Until fixed, we will track selections ourselves and use them where bugs exist.
+    const [selectionState] = React.useState<{ elements: Elements | null }>({ elements: null });
+    const onSelection = React.useCallback((elements: Elements | null) => {
+        selectionState.elements = elements;
+    }, []);
 
     return (
         <RuleEditorUiContext.Provider
@@ -40,6 +46,8 @@ export const RuleEditorView = ({ showRuleOnly, hideMinimap, zoomRange, readOnlyM
                 showRuleOnly,
                 hideMinimap,
                 zoomRange,
+                onSelection,
+                selectionState,
             }}
         >
             <Grid verticalStretchable={true} useAbsoluteSpace={true} style={{ backgroundColor: "white" }}>
diff --git a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/RuleNodeMenu.tsx b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/RuleNodeMenu.tsx
index be41e8a7e2..235c0ade37 100644
--- a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/RuleNodeMenu.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/RuleNodeMenu.tsx
@@ -1,6 +1,6 @@
 import React, { useMemo, useState } from "react";
 import { NodeTools, NodeToolsMenuFunctions } from "@eccenca/gui-elements/src/extensions/react-flow/nodes/NodeTools";
-import { Menu, MenuItem } from "@eccenca/gui-elements";
+import { Menu, MenuDivider, MenuItem } from "@eccenca/gui-elements";
 import { RuleEditorUiContext } from "../../contexts/RuleEditorUiContext";
 import { RuleEditorEvaluationContext } from "../../contexts/RuleEditorEvaluationContext";
 import { RuleEditorModelContext } from "../../contexts/RuleEditorModelContext";
@@ -42,18 +42,6 @@ export const RuleNodeMenu = ({
     return (
         <NodeTools menuButtonDataTestId={"node-menu-btn"} menuFunctionsCallback={menuFunctionsCallback}>
             <Menu>
-                <MenuItem
-                    data-test-id="rule-node-delete-btn"
-                    key="delete"
-                    icon={"item-remove"}
-                    onClick={(e) => {
-                        e.preventDefault();
-                        handleDeleteNode(nodeId);
-                    }}
-                    text={t("RuleEditor.node.menu.remove.label")}
-                    htmlTitle={"Hotkey: <Backspace>"}
-                    intent="danger"
-                />
                 <MenuItem
                     data-test-id="rule-node-clone-btn"
                     key="clone"
@@ -103,6 +91,19 @@ export const RuleNodeMenu = ({
                         )}
                     />
                 ) : null}
+                <MenuDivider />
+                <MenuItem
+                    data-test-id="rule-node-delete-btn"
+                    key="delete"
+                    icon={"item-remove"}
+                    onClick={(e) => {
+                        e.preventDefault();
+                        handleDeleteNode(nodeId);
+                    }}
+                    text={t("RuleEditor.node.menu.remove.label")}
+                    htmlTitle={"Hotkey: <Backspace>"}
+                    intent="danger"
+                />
             </Menu>
         </NodeTools>
     );
diff --git a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/SelectionMenu.tsx b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/SelectionMenu.tsx
index a96619af6a..96507a7a47 100644
--- a/workspace/src/app/views/shared/RuleEditor/view/ruleNode/SelectionMenu.tsx
+++ b/workspace/src/app/views/shared/RuleEditor/view/ruleNode/SelectionMenu.tsx
@@ -1,7 +1,6 @@
 import React from "react";
-import { EdgeTools } from "@eccenca/gui-elements/src/extensions/react-flow";
 import { XYPosition } from "react-flow-renderer/dist/types";
-import { Button } from "@eccenca/gui-elements";
+import { ContextMenu, MenuItem, MenuDivider } from "@eccenca/gui-elements";
 import { useTranslation } from "react-i18next";
 
 interface SelectionMenuProps {
@@ -13,50 +12,68 @@ interface SelectionMenuProps {
     removeSelection: () => any;
     /** Clone selection. */
     cloneSelection: () => any;
+    /** Clone selection. */
+    copySelection: () => any;
 }
 
-/** Rule edge menu. */
-export const SelectionMenu = ({ position, onClose, removeSelection, cloneSelection }: SelectionMenuProps) => {
+export const SelectionMenu = ({
+    position,
+    onClose,
+    removeSelection,
+    cloneSelection,
+    copySelection,
+}: SelectionMenuProps) => {
     const [t] = useTranslation();
     return (
-        // FIXME: CMEM-3742: Use a generic "tools" component or rename EdgeTools
-        <EdgeTools posOffset={{ left: position.x, top: position.y }} onClose={onClose}>
-            <Button
-                minimal
-                icon="item-remove"
-                data-test-id={"selection-menu-remove-btn"}
-                tooltip={t("RuleEditor.selection.menu.delete.tooltip")}
-                tooltipProps={{
-                    autoFocus: false,
-                    enforceFocus: false,
-                    openOnTargetFocus: false,
-                }}
-                small
-                onClick={() => {
-                    onClose();
-                    removeSelection();
-                }}
-            >
-                {t("RuleEditor.selection.menu.delete.label")}
-            </Button>
-            <Button
-                minimal
-                icon="item-clone"
-                data-test-id={"selection-menu-clone-btn"}
-                tooltip={t("RuleEditor.selection.menu.clone.tooltip")}
-                tooltipProps={{
-                    autoFocus: false,
-                    enforceFocus: false,
-                    openOnTargetFocus: false,
-                }}
-                small
-                onClick={() => {
-                    onClose();
-                    cloneSelection();
+        <div
+            style={{
+                position: "fixed",
+                left: position.x,
+                top: position.y,
+            }}
+        >
+            <ContextMenu
+                contextOverlayProps={{
+                    onClose,
+                    defaultIsOpen: true,
+                    autoFocus: true,
+                    interactionKind: "hover",
                 }}
+                togglerElement={<div />}
             >
-                {t("RuleEditor.selection.menu.clone.label")}
-            </Button>
-        </EdgeTools>
+                <MenuItem
+                    text={t("RuleEditor.selection.menu.copy.label")}
+                    icon="item-copy"
+                    data-test-id={"selection-menu-copy-btn"}
+                    htmlTitle={t("RuleEditor.selection.menu.copy.tooltip")}
+                    onClick={() => {
+                        onClose();
+                        copySelection();
+                    }}
+                />
+                <MenuItem
+                    text={t("RuleEditor.selection.menu.clone.label")}
+                    icon="item-clone"
+                    data-test-id={"selection-menu-clone-btn"}
+                    htmlTitle={t("RuleEditor.selection.menu.clone.tooltip")}
+                    onClick={() => {
+                        onClose();
+                        cloneSelection();
+                    }}
+                />
+                <MenuDivider />
+                <MenuItem
+                    icon="item-remove"
+                    data-test-id={"selection-menu-remove-btn"}
+                    htmlTitle={t("RuleEditor.selection.menu.delete.tooltip")}
+                    onClick={() => {
+                        onClose();
+                        removeSelection();
+                    }}
+                    intent="danger"
+                    text={t("RuleEditor.selection.menu.delete.label")}
+                />
+            </ContextMenu>
+        </div>
     );
 };
diff --git a/workspace/src/locales/manual/en.json b/workspace/src/locales/manual/en.json
index b1cef18a3a..afe7d7ec06 100644
--- a/workspace/src/locales/manual/en.json
+++ b/workspace/src/locales/manual/en.json
@@ -262,14 +262,16 @@
                     }
                 },
                 "rule-editors": {
-                    "label": "Linking editor",
+                    "label": "Linking editor / Value formula editor",
                     "shortcuts": {
                         "duplicate-nodes": "Duplicate selected nodes",
                         "undo": "Undo change",
                         "redo": "Redo change",
                         "delete": "Remove selected elements",
                         "multiselect": "Select multiple nodes",
-                        "multiselectDesc": "Select nodes either by clicking on them or by dragging a selection area"
+                        "multiselectDesc": "Select nodes either by clicking on them or by dragging a selection area",
+                        "copySelectedNodes": "Copy selected nodes to clipboard",
+                        "pasteNodes": "Paste copied nodes"
                     }
                 },
                 "workflow-editor": {
@@ -646,6 +648,10 @@
                 "clone": {
                     "label": "Clone selected nodes",
                     "tooltip": "Clones all selected nodes and inter-connections and inserts them as new selection. Following key combination also triggers this action: CTRL/CMD + d"
+                },
+                "copy": {
+                    "label": "Copy selected nodes to clipboard",
+                    "tooltip": "Copy all selected nodes and inter-connections. Can be also triggered with with following keyboard shortcut: ^Ctrl + c / ⌘Command + c. The copied elements can be inserted as copies with following keyboard shortcut: ^Ctrl + v / ⌘Command + v.The copied elements can also be inserted in editors in different tabs, windows or browsers."
                 }
             }
         },
@@ -697,7 +703,8 @@
             },
             "startEvaluation": "Start evaluation",
             "showEvaluation": "Show evaluation examples",
-            "hideEvaluation": "Hide evaluation examples"
+            "hideEvaluation": "Hide evaluation examples",
+            "copiedNotificationText": "Copied {{numberOfNodes}} to clipboard"
         }
     },
     "taskViews": {