In my use case, I was able to solve loosing the selection when using an input field with the help of a MutationObserver.
In my component I have got a state for the range which I initialize when it is connected:
private range: Range | undefined; componentWillLoad() { const selection: Selection | undefined = getSelection(); this.range = selection?.getRangeAt(0); }
getSelectionis a utility which returns theSelectionaccording browser.
Then the function which applies the color looks like following:
private selectColor($event: CustomEvent) { const selection: Selection | undefined = getSelection(); if (!selection || !$event || !$event.detail) { return; } selection?.removeAllRanges(); selection?.addRange(this.range); const observer: MutationObserver = new MutationObserver( (_mutations: MutationRecord[]) => { observer.disconnect(); this.range = selection?.getRangeAt(0); }); const anchorNode: HTMLElement | undefined = getAnchorNode(selection); observer.observe(anchorNode, {childList: true}); document.execCommand('foreColor', false, $event.detail.value); What's happening: I get the selection, remove all ranges and add the one I preserve as state.
Then I attach a mutation observer on the selection anchor node. For such purpose I use a utility which return either the anchor node or its parent in case of a text or comment would be selected.
Then I call the execCommand.
Once the observer kicks, I query the selection (which is at that point the modified node of the document, not the input) for the new range and save it to my state.
Hope it helps.