WebForms Core 2.1 is coming soon from Elanat. The new version introduces a collection of capabilities designed to further expand the server-driven approach of WebForms Core. One of these new capabilities is Morphing.
Morphing provides a way to synchronize an existing DOM element with a new HTML structure without necessarily replacing the existing element itself.
This makes it possible to update HTML structures while preserving the identity of existing DOM elements.
Morphing
Morphing is a DOM synchronization mechanism that compares an existing HTML element with a new HTML structure and applies the required changes to the existing DOM.
Unlike a traditional replacement operation such as:
element.outerHTML = html;
Morphing does not simply discard the existing element and create another one.
Instead, it analyzes the existing element and the new element and performs the necessary operations:
- Add new attributes
- Update existing attributes
- Remove attributes that no longer exist
- Add new child elements
- Update existing child elements
- Remove obsolete child elements
- Match elements using
idandcb-data-id - Preserve existing DOM element identity whenever possible
- Preserve registered event listeners when new Nodes have to be created
The goal is to make the smallest necessary changes to the DOM.
Reflection vs Morphing
WebForms Core 2.1 contains both Reflection and Morphing, but they serve different purposes.
Reflection is primarily a merge operation.
For example, if the target contains:
<div id="userCard">
<h3>User</h3>
</div>
and the source contains:
<div class="premium">
<button>VIP</button>
</div>
Reflection can merge the source into the target, adding the class and child without treating the source as a complete replacement definition.
Morphing has a different philosophy.
The source represents the desired structure.
If the source does not contain an element or attribute that exists in the target, Morphing can remove it.
Therefore:
Reflection
Target + Source
↓
Merge
Morphing
Target → Source
↓
Synchronize
This distinction makes both mechanisms useful for different types of server-driven UI operations.
The WebForms Core API
Morphing can be invoked from the WebForms class.
The first method accepts HTML directly:
SetMorph(string InputPlace, string Tag)
The second method uses an existing element as the source:
SetMorphByOutputPlace(string InputPlace, string OutputPlace)
For example:
form.SetMorphByOutputPlace(
"userCard",
"userCardTemplate"
);
Here:
-
userCardis the destination element. -
userCardTemplateis the source element.
The developer does not need to manually write JavaScript to perform the DOM synchronization.
A Complete Example
Consider the following page.
Initially, the page contains a user card:
<div id="userCard"
class="card"
data-user="123"
style="border: 1px solid #ccc; padding: 10px;">
<h3>User</h3>
<p id="userEmail">
Email: user@example.com
</p>
<button id="editButton"
class="btn-edit"
onclick="editUser()">
Edit
</button>
<span id="oldTag">
Old tag
</span>
</div>
A template describes the new state of this element:
<template id="userCardTemplate">
<div id="userCard"
class="card premium"
data-user="456"
data-role="admin"
style="background-color: #f0f8ff; border: 2px solid blue; margin: 5px;">
<h3>User</h3>
<button id="editButton"
class="btn-vip"
onclick="VIP()">
VIP
</button>
<span id="newTag">
New tag
</span>
</div>
</template>
The controller can perform the Morph operation with:
using CodeBehind;
public partial class MorphController : CodeBehindController
{
public void PageLoad(HttpContext context)
{
// Checking "Post-Back" in Request Headers for Maintain Interactive mode when Refreshing the Page in the Browser.
if (context.Request.Query.ContainsKey("set-morph") && context.Request.Headers.ContainsKey("Post-Back"))
{
SetMorph_OnClick(context);
return;
}
}
private void SetMorph_OnClick(HttpContext context)
{
WebForms form = new WebForms();
form.SetMorphByOutputPlace("userCard", "userCardTemplate");
IgnoreAll();
Write(form.Response());
}
}
The page can trigger the operation with a normal WebForms Core request:
<a href="?set-morph">Click to Link for Morph</a>
What happens during Morphing?
Before Morphing, the target is:
<div id="userCard"
class="card"
data-user="123"
style="border: 1px solid #ccc; padding: 10px;">
<h3>User</h3>
<p id="userEmail">
Email: user@example.com
</p>
<button id="editButton"
class="btn-edit"
onclick="editUser()">
Edit
</button>
<span id="oldTag">
Old tag
</span>
</div>
The source describes:
<div id="userCard"
class="card premium"
data-user="456"
data-role="admin"
style="background-color: #f0f8ff; border: 2px solid blue; margin: 5px;">
<h3>User</h3>
<button id="editButton"
class="btn-vip"
onclick="VIP()">
VIP
</button>
<span id="newTag">
New tag
</span>
</div>
Morphing compares these two structures and applies the necessary changes.
The resulting DOM becomes:
<div id="userCard"
class="card premium"
data-user="456"
style="background-color: #f0f8ff; border: 2px solid blue; margin: 5px;"
data-role="admin">
<h3>User</h3>
<button id="editButton"
class="btn-vip"
onclick="VIP()">
VIP
</button>
<span id="newTag">
New tag
</span>
</div>
Attribute Morphing
Attributes are synchronized between the target and source.
For example:
data-user="123"
becomes:
data-user="456"
The new attribute:
data-role="admin"
is added.
The class:
class="card"
becomes:
class="card premium"
And the style is updated according to the source.
Attributes that exist in the target but no longer exist in the source are removed.
Therefore Morphing effectively synchronizes the attribute set:
Target attributes
↓
Compare
↓
Source attributes
↓
Add / Update / Remove
Child Element Morphing
Morphing also operates recursively on child Nodes.
In the example, this element:
<p id="userEmail">
Email: user@example.com
</p>
does not exist in the new structure.
Therefore it is removed.
Likewise:
<span id="oldTag">
Old tag
</span>
is removed.
At the same time:
<span id="newTag">
New tag
</span>
is added.
The existing:
<h3>User</h3>
is retained and synchronized.
Element Matching
One of the important parts of Morphing is determining whether a new element corresponds to an existing element.
WebForms Core uses identifiers such as:
id="editButton"
and:
cb-data-id="..."
for this purpose.
For example, both the old and new structures contain:
<button id="editButton">
Therefore Morphing can recognize that they represent the same DOM element.
The existing Node can consequently be retained while its attributes and contents are updated.
This is different from simply deleting the old button and creating a completely new button.
Event Listeners
DOM cloning has an important limitation:
cloneNode(true)
does not copy event listeners registered through addEventListener.
WebForms Core Morphing therefore integrates with the WebForms Core event registry.
When Morphing needs to create a new Node, registered event listeners can be transferred to the new Node.
This is particularly important for applications that dynamically update their interface while maintaining interactive behavior.
The principle is:
Existing Node
↓
Keep Node
↓
Keep its event listeners
New Node
↓
Create Node
↓
Transfer registered listeners
This allows Morphing to modify the DOM without unnecessarily destroying its interactive state.
Why use <template>?
A <template> element is particularly convenient as the source of a Morph operation.
For example:
<template id="userCardTemplate">
<div id="userCard">
...
</div>
</template>
The template provides a declarative representation of the desired HTML structure without displaying that structure directly on the page.
This makes it possible to separate:
Visible DOM
+
Desired DOM structure
while keeping the desired structure inside the HTML document.
WebForms Core can use the internal content of the template as the source of the Morph operation.
Morphing is not DOM Replacement
A conventional replacement might effectively perform:
element.replaceWith(newElement);
The consequence is that the original DOM element is destroyed.
Morphing instead attempts to preserve the existing element:
Replace:
OLD NODE
↓
destroy
↓
NEW NODE
Morph:
OLD NODE
↓
compare
↓
modify
↓
same NODE
This distinction becomes particularly useful for interactive interfaces.
An element can have:
- browser state
- registered event listeners
- references from application code
- associated DOM state
and Morphing can update its structure without necessarily discarding the element itself.
Server-Driven UI
Morphing fits naturally into the architecture of WebForms Core.
The server does not need to send an entire page.
Instead, it can describe the desired UI operation:
form.SetMorphByOutputPlace(
"userCard",
"userCardTemplate"
);
WebForms Core then performs the DOM synchronization on the client.
This follows the broader WebForms Core philosophy of treating communication between server and browser as an instruction stream rather than simply transferring complete HTML documents.
The server determines what operation should happen, while WebForms Core performs that operation in the browser.
Morphing vs Reflection
The two capabilities can be summarized as follows:
| Feature | Reflection | Morphing |
|---|---|---|
| Preserve target element | Yes | Yes |
| Add attributes | Yes | Yes |
| Update attributes | Yes | Yes |
| Remove obsolete attributes | No, merge-oriented | Yes |
| Add children | Yes | Yes |
| Update children | Limited/merge-oriented | Yes |
| Remove obsolete children | No | Yes |
| Recursive synchronization | No/limited | Yes |
Match by id / cb-data-id
|
— | Yes |
| Preserve DOM identity | Yes | Yes |
| Intended purpose | Merge | Synchronize |
In simple terms:
Reflection merges. Morphing synchronizes.
Conclusion
Morphing in WebForms Core 2.1 provides a declarative way to transform an existing DOM structure into a new structure while minimizing unnecessary DOM replacement.
Instead of manually writing JavaScript to:
find element
→ compare attributes
→ remove attributes
→ update attributes
→ find children
→ remove children
→ create children
→ preserve events
the server can simply describe the desired operation:
form.SetMorphByOutputPlace(
"userCard",
"userCardTemplate"
);
WebForms Core performs the synchronization on the client.
With Reflection for merging and Morphing for structural synchronization, WebForms Core 2.1 adds two complementary mechanisms for declaratively manipulating the DOM from server-side code—without requiring a conventional front-end framework.
Related links
WebForms Core in GitHub:
https://github.com/webforms-core
Top comments (0)