Morphlex is a ~3KB (gzipped) DOM morphing library that transforms one DOM tree to match another while preserving element state and making minimal changes.
- No cascading mutations from inserts. Simple inserts should be one DOM operation.
- No cascading mutations from removes. Simple removes should be one DOM operation.
- No cascading mutations from partial sorts. Morphlex finds the longest increasing subsequence for near perfect partial sorts.
- It uses
moveBeforewhen available, preserving state. - It uses
isEqualNode, but in a way that is sensitive to the value of form inputs. - It uses id sets, inspired by Idiomorph, so ids can help to identify their parent nodes.
npm install morphlex
Or use it directly from a CDN:
<scripttype="module">import{morph}from"https://www.unpkg.com/morphlex@latest/dist/morphlex.min.js"</script>import{morph,morphInner}from"morphlex"// Morph the entire elementmorph(currentNode,newNode)// Morph only the children of the current nodemorphInner(currentNode,newNode)// Morph the entire documentmorphDocument(document,newDocument)Both morph and morphInner accept an optional third parameter for configuration:
morph(currentNode,newNode,{preserveChanges: true,beforeNodeAdded: (parent,node,insertionPoint)=>{console.log("Adding node:",node)returntrue// return false to prevent addition},})preserveChanges: Whentrue, preserves modified form inputs during morphing. This prevents user-entered data from being overwritten. Default:falsebeforeNodeVisited: Called before a node is visited during morphing. Returnfalseto skip morphing this node.afterNodeVisited: Called after a node has been visited and morphed.beforeNodeAdded: Called before a new node is added to the DOM. Returnfalseto prevent adding the node.afterNodeAdded: Called after a node has been added to the DOM.beforeNodeRemoved: Called before a node is removed from the DOM. Returnfalseto prevent removal.afterNodeRemoved: Called after a node has been removed from the DOM.beforeAttributeUpdated: Called before an attribute is updated on an element. Returnfalseto prevent the update.
morph(currentNode,newNode,{beforeAttributeUpdated: (element,name)=>{if(element.tagName==="DETAILS"&&name==="open")returnfalsereturntrue},})This can be useful for preserving UI state that your backend does not track, such as whether a <details> element is open.
afterAttributeUpdated: Called after an attribute has been updated on an element.beforeChildrenVisited: Called before an element's children are visited during morphing. Returnfalseto skip visiting children.afterChildrenVisited: Called after an element's children have been visited and morphed.
