How to implement table resizing?

I am trying to implement table resizing (by dragging along the table borders).

My initial attempt was to attach an angular directive (resizable) after creating the table. Something like this (just on one td for now)-

    element = document.querySelectorAll('td')[0]

I added the required attributes in td’s node definition. This works but after the function ends, prosemirror adds a new table and deletes the old compiled one, probably because I am directly mutating the dom via the directive.

After going through this post, I tried to implement this via a nodeview for td

constructor(private node, private view, private getPos) {
    let {dom, contentDOM} = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node));

    let $injector = angular.element('body').injector();
    let $compile = $injector.get('$compile');
    let $rootScope = $injector.get('$rootScope');

    this.dom = $compile(this.dom)($rootScope)[0]
    this.contentDOM = this.dom;

but this gives a simple table. On removing the contentDOM property, it works but the table becomes uneditable.

I also tried this with plain javascript using something similar to this fiddle, but have the same problem as before.

Are the child nodes replacing the divs being created here? What would be the right way to go about this.

Thank You

You don’t need to create a node view, just go through a ProseMirror transaction when doing the resizing (i.e. do something like setNodeType to update the attribute you want to update).

The problem is that to enable resizing, I am adding small divs near the table border which the user can grab and drag. If I try to add these after creating the table, prosemirror automatically removes them. Can (should) this be done without nodeviews? I am currently doing it like so (in the td’s nodeview’s constructor)-

  constructor( node, view, getPos ) {
    let td = document.createElement("td"); = 'relative';
    let content = document.createElement("div");
    var grip = document.createElement('div');
    grip.innerHTML = " "; = "0"; = "0"; = "0"; = '5px'; = 'absolute'; = 'col-resize';
    grip.addEventListener('mousedown', function (e) {
        tdElm = td;
        startOffset = td.offsetWidth - e.pageX;
    view.dom.addEventListener('mouseup', function (e) {
          $.logInfo("position", getPos(), tdElm);
          let tr =;
          let attrs=Object.assign({}, node.attrs);
  		  attrs.width = startOffset + e.pageX + 'px';
          tr.setNodeType(getPos(), node.type, attrs) 
          tdElm = undefined;

    this.dom = td;
    this.contentDOM = content;

I am not able to understand why mouseup event is being called on the same td m times (m = the number of columns) and why getPos() is returning undefined

Right, adding nodes to the document won’t work (it’ll be detected as a DOM change, and the surrounding content will immediately be re-parsed and re-rendered). A node view can help there, or you could just style the regular cells with some kind of resize-handle-looking border and capture events on the whole editor, inspecting them to see if they landed in such a border.

You appear to be adding a new event listener to the view’s whole DOM every time a node view is initialized. This will clearly lead to a lot of identical handlers.