JSFiddle - React, Tailwind, and code Playground

HTML

<p class="parent" contenteditable="true">Bacon ipsum dolor amet jowl chicken pork loin <span class="move">[move text]</span>tail. Short ribs meatball
    <br>bresaola beef boudin hamburger, cow rump swine. Pork belly ribeye leberkas venison
    <br>ground <span class="move">[move text]</span>round shoulder pork <span class="move">[move text]</span>chop, strip steak drumstick doner t-bone alcatra pancetta turkey boudin.
    <br>Filet mignon pork chop tongue t-bone jowl strip steak. Cow spare ribs bresaola, tail
    <br>chicken brisket pastrami shank strip steak ribeye biltong pancetta short
    <br>ribs corned beef meatloaf. <span class="move">[move text]</span>Hamburger meatloaf pig strip steak.</p>

CSS

.parent {
    background-color: #F7F7F7;
}
.move {
    background-color: khaki;
    margin: 0 2px;
}

JavaScript

$('p[contenteditable]').on('keydown', function (e) { 
    // Only handle event if ctrl+left / ctrl+right
    if (!e.ctrlKey || (e.which != 37 && e.which != 39)) return;
    // and selection is in a span.move
    var sel = document.getSelection();
    var node = sel.anchorNode;
    if (!node || node != sel.focusNode) return;
    // Text "[move text]" is in selection
    if (node.nodeType == Node.TEXT_NODE) {
        node = node.parentNode;
    }
    if (!node || node.nodeName != 'SPAN' || node.className != 'move') return;

    moveSpan(node, e.which == 37); // 37: left, 39: right
    e.preventDefault();
    e.stopPropagation();
});

function moveSpan (span, toLeft) {
    var left = span.previousSibling;
    var right = span.nextSibling;

    if (!left || left.nodeType != Node.TEXT_NODE || !right || right.nodeType != Node.TEXT_NODE) return;
    if (toLeft && !left.length) return;
    if (!toLeft && !right.length) return;

    if (toLeft) {
        right.insertData(0, left.data[left.length - 1]);
        left.deleteData(left.length - 1, 1);
    } else {
        left.appendData(right.data[0]);
        right.deleteData(0, 1);
    }
}