When you render HTML on the backend – for example with Phlex – how do you get it to the browser? One way is to have the user click a link, submit a form, or reload the page. Alternatively, in response to some user interaction or push event, you can fetch new HTML from JavaScript and alter the DOM locally.
myElement.outerHTML = newHTML
The problem with these approaches is that they lose state. Form inputs lose focus, text selection and scroll position are reset, event listeners and observers become detached, popovers and dialogs disappear, iframes reload and CSS animations are disrupted.
DOM morphing attempts to solve this by carefully comparing the original DOM tree to the new DOM tree and “morphing” the original tree to match the new tree.
There are many established morphing libraries to choose from. Just to name a few, these are:
Today, I’m presenting my take on DOM morphing, Morphlex 1.0.
node identification problem
The biggest problem in DOM morphing is node identification. How do you determine whether a node in the original DOM is identical to another node in the new DOM? it could have happened Have been taken, taken out Or update Or a new node could be inserted in its place.
have to rely on a solution id Property. If a node in the new DOM has the same id As for a node in the original DOM, you can assume it is the same node, even if its contents have changed.
The unfortunate reality is that most DOM is lacking id Property. Ideomorph pioneered an interesting technique to improve upon this.
since id Attributes are unique on a page and since elements can have only one parent node, the IDs of child nodes can be used to uniquely identify their parent nodes at any depth level.
This works because the set of children IDs of any node is unique at any level.
Essentially the idiomorph scans the DOM for elements with an ID and then walks through each element’s ancestors, adding that element. id To set the ancestor ID.
Let’s say you have some DOM that looks like this.
<section>
<article id="article-1">
<div>
<h1 id="heading-1">Hello!h1>
div>
article>
section>
If we visualize the calculated ID sets as pseudo HTML attributes, they will look like this.
<section id-set="article-1 heading-1">
<article id="article-1" id-set="article-1 heading-1">
<div id-set="heading-1">
<h1 id="heading-1" id-set="heading-1">Hello!h1>
div>
article>
section>
You can see how also
idIt can still be uniquely identified among its peers at its level by its set of children’s IDs.
While this certainly improves things, it’s still not perfect. When there is no ID nearby, most DOM morphing libraries fall back to selecting the next element with the same tag name.
Unfortunately, this often leads to unnecessary sweeping in many realistic scenarios.
insert item
A common scenario is to transform a new tree that is exactly the same as the original tree, except that there is a new node in the list.
In this example, when there is no ID, the algorithm selects the next element with the same tag name and changes it to match the corresponding element in the new DOM.

Item 1 is the same on both sides but since Item 2 was changed to the new item, Item 3 now needs to be changed to Item 4, and Item 4 needs to become Item 5, and so on…
Ideally, the algorithm will be able to look ahead and see that there is a corresponding element in the original tree for all elements except one in the new tree. it just could happen Pour New element in perfect condition.

It’s essentially the same thing as when deleting nodes. Item 2 is transformed into Item 3, which means Item 3 needs to be transformed into Item 4 and Item 4 needs to be transformed into Item 5. After transforming item 5 into item 6, we are left with one last node that needs to be removed.

Ideally, the algorithm will instead look ahead and see that the original DOM already has a copy of all the items in the new DOM and so only item 2 remains to be removed.

Sorting things is just as bad. In this example, we’re moving item 3 up just two places, but we have to make four changes to get there.

Ideally, we would find the longest increasing sequence – in this case, 1, 2, 4, 5, 6 and 7 and ignore these nodes as they are already in the correct position. We can then put the remaining items in place in one step.

How does Morphlex solve these problems?
At each level of the tree, Morphex has a matching algorithm that tries to find the best match between elements in the original tree and the new tree.
First, it creates a set of elements on the left and another set of elements on the right. It also creates a series of matches.
It iterates over each element on the left and compares them with each element on the right. uses initial comparison isEqualNode To see if the nodes are already exactly the same. If it finds the correct match, it removes the elements from their respective set and writes them to the correct index. Matchbox array.
Then it repeats again, matching the exact ID, and then the ID from the set, then the tag name and attributes name, href Or srcAnd finally by tag name alone – or if it’s an input, by tag name and input type.
As it progresses, it removes matched elements from their respective sets, so the iterations on each pass become cheaper and cheaper.
After matching, we are left with a set of elements from the old tree to remove, a set of elements from the new tree to insert, and an array that maps the old elements to match the new elements.
This array of matches is used to calculate the longest increasing sequence for optimal sorting.
Finally, everything is moved to its place using moveBefore Which maintains all the original positions. If moveBefore not available, insertBefore Is used instead.
You might be wondering how we can get rid of its use isEqualNodesince isEqualNode For example, it can’t tell whether you’ve changed the value of an input element.
To overcome this, we first iterate over all form inputs in the original tree and add a special attribute if the current value is different from the default value (if the value has been changed by a user). This special feature allows isEqualNode To avoid change detection, we can silently remove a particular attribute later in the process.
Having said that, my preference is to leave the modified input values in place, as they were probably intended by the user. Morphlex offers configuration options preserveChanges For this.
Display
It’s hard to say how Morphlex compares to Morphdom/Ideomorph as they effectively do different things. For example, there are scenarios where MorphDOM will simply replace what Morphlex would spend time matching and transferring.
However Morphlex usually does much less work than other DOM morphing libraries in real-world scenarios due to its design, so it is very fast. In my limited experience the performance and accuracy is good enough for creating complete document forms.
Morphlex is released under the MIT License. If you find any bugs please let me know.
Enjoy ❤️