useEditor()
Hook
A Hook that provides methods and state information associated with the entire editor.
const { connectors, actions, query, ...collected } = useEditor(collector);
Reference
Parameters
collector(state: EditorState, query: Query) => CollectedA function that collects relevant state information from the editor state. The component will re-render when the values returned by this function changes.
Returns
- Object
connectorsObjectselect(dom: HTMLElement, nodeId: NodeId) => HTMLElementSpecifies the DOM that when clicked will in turn click the specified Node's user componenthover(dom: HTMLElement, nodeId: NodeId) => HTMLElementSpecifies the DOM that when hovered will in turn hover the specified Node's user componentdrag(dom: HTMLElement, nodeId: NodeId) => HTMLElementSpecifies the DOM that when dragged will move the specified Node's user component. Only applicable if the component is rendered as an immediate child of a <Canvas /> component.create(dom: HTMLElement, userElement: React.ReactElement) => HTMLElementSpecifies the DOM that when dragged will create a new instance of the specified User Element at the drop location.
actionsActionMethodsadd(nodes: Node, parentId?: NodeId, index?: number) => voidAdd a Node to the given parent node ID at the specified index. By default the parentId is the id of the Root NodeaddNodeTree(tree: NodeTree, parentId?: NodeId) => voidAdd a NodeTree to the given parent node ID at the specified index. By default the parentId is the id of the Root NodeclearEvents() => voidResets the editors events statedelete(nodeID: NodeId) => voidDelete the specified Nodedeserialize(data: SerializedNodes | string) => voidRecreate Nodes from a SerializedNodes object/json. This will clear all the current Nodes in the editor state with the recreated Nodesmove(nodeId: NodeId, targetParentId: NodeId, index: number) => voidMove a Node to the specified parent Node at the given index.setProp(nodeId: NodeId, update: (props: Object) => void) => voidManipulate the props of the given NodesetCustom(nodeId: NodeId, update: (custom: Object) => void) => voidManipulate the custom values of the given NodesetHidden(nodeId: NodeId, bool: boolean) => voidWhen set to true, the User Component of the specified Node will be hidden, but not removedsetOptions(options: Object) => voidUpdate the editor's options. The options object passed is the same as the <Editor /> props.selectNode(nodeId: NodeId | null) => voidSelect the specified node. You can clear the selection by passing `null`historyundo() => voidUndo the last recorded actionredo() => voidRedo the last undone actionignore() => ActionMethodsRun an action without recording its changes in the historythrottle(throttleRate: number = 500) => ActionMethodsRun an action while throttling its changes recorded to the history. This is useful if you need to group the changes made by a certain action as a single history record
queryQueryMethodsgetSerializedNodes() => SerializedNodesReturn the current Nodes into a simpler form safe for storageserialize() => StringReturn getSerializedNodes() in JSONgetOptions() => ObjectGet the options specified in the <Editor /> componentgetDropPlaceholder(sourceNodeId: NodeId, targetNodeId: NodeId, pos: {x: number, y: number}, nodesToDOM?: (node: Node) => HTMLElement = node => node.dom)Given the target Node and mouse coordinates on the screen, determine the best possible location to drop the source Node. By default, the Node's DOM property is taken into consideration.node(id: NodeId) => NodeHelpersReturns an object containing helper methods to describe the specified Node. Click here for more information.parseReactElement(element: React.ReactElement) => ObjecttoNodeTree(normalize?: (node: Node, jsx: React.ReactElement) => void) => NodeTreeParse a given React element into a NodeTree
parseSerializedNode(node: SerializedNode) => ObjecttoNode(normalize?: (node: Node) => void) => NodeParse a serialized Node back into it's full Node form
parseFreshNode(node: FreshNode) => ObjecttoNode(normalize?: (node: Node) => void) => NodeParse a fresh/new Node object into it's full Node form, ensuring all properties of a Node is correctly initia lised. This is useful when you need to create a new Node.
historycanUndo() => booleanReturns true if undo is possiblecanRedo() => booleanReturns true if redo is possible
inContextbooleanReturns false if the component is rendered outside of the <Editor />. This is useful if you are designing a general component that you also wish to use outside of Craft.js....collectedCollectedThe collected values returned from the collector
 
Examples
Collecting state information
import {useEditor} from "@craftjs/core";
const Example = () => {
  const { hoveredNodeId } = useEditor((state) => ({
    hoveredNodeId: state.events.hovered
  }));
  return (
    <div>
      The ID of the node currently being hovered is: {hoveredNodeId}
    </div>
  )
}
Updating props
import {useEditor} from "@craftjs/core";
const Example = () => {
  const { selectedNodeId, actions: {setProp} } = useEditor((state) => ({
    selectedNodeId: state.events.selected
  }));
  return (
    <a
      onClick={_ => {
        setProp(selectedNodeId, props => {
          props.text = "new value";
        });
      }}
    >
      Update
    </a>
  )
}
Creating new Nodes
import {useEditor} from "@craftjs/core";
const Example = () => {
  const { query, actions } = useEditor((state, query) => ({
    hoveredNodeId: state.events.hovered
  }));
  return (
    <div>
      <a onClick={() => {
        const nodeTree = query.parseReactElement(<h2>Hi</h2>).toNodeTree();
        actions.addNodeTree(nodeTree);
      }}>
        Add a new Node from a React Element
      </a>
        
      <a onClick={() => {
        // A fresh Node is a partial Node object
        // where only the data.type property is required
        const freshNode = {
            data: {
                type: 'h1'
            }
        };
        
        // Create a new valid Node object from the fresh Node
        const node = query.parseFreshNode(freshNode).toNode();
        actions.add(node, 'ROOT');
      }}>
        Add a new Node from a Node object
      </a>
    </div>
  )
}
Hiding and Deleting a Node
const Example = () => {
  const {selectedNodeId, actions} = useEditor((state) => ({
    selectedNodeId: state.events.selected
  }));
  return selectedNodeId && (
    <div>
      <h2>Node selected: {selectedNodeId}</h2>
      <a onClick={() => actions.hide(selectedNodeId)}>Hide</a>
      <a onClick={() => actions.delete(selectedNodeId)}>Delete</a>
    </div>
  )
}
Moving a Node
const Example = () => {
  const [sourceId, setSourceId] = useState();
  const [targetId, setTargetId] = useState();
  
  const {selectedNodeId, actions, query} = useEditor((state) => ({
    selectedNodeId: state.events.selected
  }));
  return selectedNodeId && (
    <div>
      <h2>Node selected: {selectedNodeId}</h2>
      <div>
        <input type="text" value={sourceId} placeholder="Source" disabled />
        <button onClick={() => selectedNodeId && setSourceId(selectedNodeId)}>Set selected Node as source</button>
      </div>
      <div>
        <input type="text" value={targetId} placeholder="Target" disabled />
        <button onClick={() => selectedNodeId && setTargetId(selectedNodeId)}>Set selected Node as target</button>
      </div>
      {
        sourceId && targeId ? (
          <button onClick={() => {
            try {
              // .canDropInParent will throw an error message if the conditions failed
              query.canDropInParent(sourceId, targetId); 
              actions.move(sourceId, targetId);
            } catch (e) {
              console.error(e.message);
            } 
          }}>Move Node</button>
        )
      }
    </div>
  )
}
Getting the currently selected Node's descendants
Query methods are also accessible from within the collector function.
import {useEditor} from "@craftjs/core";
const Example = () => {
  const { selectedDescendants } = useEditor((state, query) => ({
    selectedDescendants: state.events && query.node(state.events.selected).descendants().map(node => node.id)
  }));
  return (
    <ul>
      {
        selectedDescendants && selectedDescendants.map(id => <li>{id}</li> )
      }
    </ul>
  )
}
Displaying Drop Indicator for the best possible drop location
const Example = () => {
  const [screenClick, setScreenClick] = useState(false);
  const [sourceId, setSourceId] = useState();
  const [targetId, setTargetId] = useState();
  
  const {selectedNodeId, actions, query} = useEditor((state) => ({
    selectedNodeId: state.events.selected
  }));
  const disableScreenClick = useEffect((e) => {
     if(e.key === "Escape") {
       setScreenClick(false);
    }
  }, [screenClick]);
  const clickOnScreen = useEffect((e) => {
    const {clientX: x, clientY: y} = e;
    const dropIndicator = query.getDropIndicator(sourceId, targetId, {x, y});
    actions.setDropIndicator(dropIndicator);
  }, [screenClick]);
  
  useEffect(() => {
    window.addEventListener("click", clickOnScreen);
    window.addEventListener("keyup", disableScreenClick);
    return (() => {
      window.removeEventListener("click", clickOnScreen);
      window.removeEventListener("keyup", disableScreenClick);
    })
  }, [clickOnScreen, disableScreenClick]);
  return selectedNodeId && (
    <div>
      <h2>Node selected: {selectedNodeId}</h2>
      <div>
        <input type="text" value={sourceId} placeholder="Source" disabled />
        <button onClick={() => selectedNodeId && setSourceId(selectedNodeId)}>Set selected Node as source</button>
      </div>
      <div>
        <input type="text" value={targetId} placeholder="Target" disabled />
        <button onClick={() => selectedNodeId && setTargetId(selectedNodeId)}>Set selected Node as target</button>
      </div>
      {
        sourceId && targeId ? (
          <button onClick={() => {
            setScreenClick(true);
          }}>
            {screenClick ? "Click anywhere on the screen to display indicator" : "Start"}
          </button>
        )
      }
    </div>
  )
}
History
import {useEditor} from "@craftjs/core";
const Example = () => {
  const { canUndo, canRedo, actions } = useEditor((state, query) => ({
    canUndo: query.history.canUndo(),
    canRedo: query.history.canRedo()
  }));
  return (
    <div>
      {
        canUndo && <button onClick={() => actions.history.undo()}>Undo</button>
      }
      {
        canRedo && <button onClick={() => actions.history.redo()}>Redo</button>
      }
      <button onClick={() => {
        // The following action will be ignored by the history
        // Hence, it will not be possible to undo/redo the following changes
        actions.history.ignore().setProp("ROOT", props => prop.darkMode = !prop.darkMode);
      }}>
        Toggle
      </button>
      <input type="text" onChange={e => {
        // In cases where you need to perform an action in rapid successions
        // It might be a good idea to throttle the changes
        actions.history.throttle().setProp("ROOT", props => props.text = e.target.value);
      }} placeholder="Type some text" />
    </div>
  )
}
Legacy API
For Class Components, use connectEditor instead.
Higher-Order Component
Parameters
collector(node: Node) => CollectedA function that collects relevant state information from the corresponding Node. The component will re-render when the values returned by this function changes.
Injected Props
...useEditor(collector)ObjectIdentical return values as the useEditor() hook above
Example
import { connectEditor } from "@craftjs/core";
class SidebarInner extends React.Component {
  render() {
    const { actions, query, enabled, currentSelectedNodeId } = this.props;
    return (
      <div>
        <input type="checkbox" value={enabled} onChange={
          e => actions.setOptions(options => options.enabled = !enabled)
        } />
        <button 
          onClick={() => {
            console.log(query.serialize())
          }}
        >
            Serialize JSON to console
        </button>
      </div>
    )
  }
}
export const Sidebar = connectEditor((state) => ({
  currentSelectedNodeId: state.events.selected
}))(SidebarInner);