DEV Community

Cover image for Morphing Feature in WebForms Core 2.1
Elanat Framework
Elanat Framework

Posted on

Morphing Feature in WebForms Core 2.1

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 id and cb-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:

  • userCard is the destination element.
  • userCardTemplate is 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>
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: user@example.com
    </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: user@example.com
</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 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
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

Top comments (0)