Manually triggering a node click

I have a plugin that enables custom nodes. These nodes do not have explicit NodeViews and rely on the toDOM function in their spec. The plugin constructor sets up a click handler with

  handleClickOn: this.handleNodeClick,

and handleNodeClick triggers a modal which allows the user to edit the underlying value of the node. I see the currentTarget of the event passed to the handler is the document element, so ProseMirror is delegating events to <html>. OK, that seems fine. But why when I run $(customNodeEl).click() does it not trigger the handler? I dug through the prosemirror-view source in search of the answer, which seems to have something to do with click events not being bound directly to click but rather mousedown + some gateway logic + mouseup. The reason I’d like to trigger it programmatically is to automatically open the modal when the custom node is first inserted into the DOM. I saw Callback when NodeView is inserted into DOM and think I could achieve the same inside the toDOM with a requestAnimationFrame, but the synthetic click would have to actually fire the callback.

Update: I got it working, though this does feel like quite a hack.

This gets called when the user causes a new custom node to enter the document:

const createCustomNode = (state, attrs, nodeType, marks) => {
  const mergedAttrs = { ...attrs, shouldOpenModal: true };

  return state.schema.node(nodeType, mergedAttrs, null, marks);

And I updated the nodeSpec to expect it

const nodeSpec = {
  attrs: {
    // Ephemeral property, not stored in DOM
    shouldOpenModal: { default: false },
  toDOM: node => createNodeElement(node.attrs),

And used the passed value to simulate a “click”…

const createNodeElement = ({
}) => {
  const wrapper = document.createElement('span');

  if (shouldOpenModal) {

  return wrapper;

…which happens once the new node is in the DOM.

const triggerModalAfterInsertion = el => {
 requestAnimationFrame(function() {
    const rect = el.getBoundingClientRect();
    const eventCoords = { clientX: rect.x, clientY: rect.y, bubbles: true };
    const mousedown = new MouseEvent('mousedown', eventCoords);
    const mouseup = new MouseEvent('mouseup', eventCoords);