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;
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
and the source contains:
<div class="premium">
<button>VIP</button>
</div>
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode
The second method uses an existing element as the source:
SetMorphByOutputPlace(string InputPlace, string OutputPlace)
Enter fullscreen mode Exit fullscreen mode
For example:
form.SetMorphByOutputPlace(
"userCard",
"userCardTemplate"
);
Enter fullscreen mode Exit fullscreen mode
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: [email protected]
</p>
<button id="editButton"
class="btn-edit"
onclick="editUser()">
Edit
</button>
<span id="oldTag">
Old tag
</span>
</div>
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
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());
}
}
Enter fullscreen mode Exit fullscreen mode
The page can trigger the operation with a normal WebForms Core request:
<a href="?set-morph">Click to Link for Morph</a>
Enter fullscreen mode Exit fullscreen mode
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: [email protected]
</p>
<button id="editButton"
class="btn-edit"
onclick="editUser()">
Edit
</button>
<span id="oldTag">
Old tag
</span>
</div>
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
Attribute Morphing
Attributes are synchronized between the target and source.
For example:
data-user="123"
Enter fullscreen mode Exit fullscreen mode
becomes:
data-user="456"
Enter fullscreen mode Exit fullscreen mode
The new attribute:
data-role="admin"
Enter fullscreen mode Exit fullscreen mode
is added.
The class:
class="card"
Enter fullscreen mode Exit fullscreen mode
becomes:
class="card premium"
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
Child Element Morphing
Morphing also operates recursively on child Nodes.
In the example, this element:
<p id="userEmail">
Email: [email protected]
</p>
Enter fullscreen mode Exit fullscreen mode
does not exist in the new structure.
Therefore it is removed.
Likewise:
<span id="oldTag">
Old tag
</span>
Enter fullscreen mode Exit fullscreen mode
is removed.
At the same time:
<span id="newTag">
New tag
</span>
Enter fullscreen mode Exit fullscreen mode
is added.
The existing:
<h3>User</h3>
Enter fullscreen mode Exit fullscreen mode
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"
Enter fullscreen mode Exit fullscreen mode
and:
cb-data-id="..."
Enter fullscreen mode Exit fullscreen mode
for this purpose.
For example, both the old and new structures contain:
<button id="editButton">
Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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>
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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);
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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"
);
Enter fullscreen mode Exit fullscreen mode
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 byid / 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
Enter fullscreen mode Exit fullscreen mode
the server can simply describe the desired operation:
form.SetMorphByOutputPlace(
"userCard",
"userCardTemplate"
);
Enter fullscreen mode Exit fullscreen mode
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