" MicromOne: Two Pragmatic Ways to “Hack” the DOM in Model-Driven Apps

Pagine

Two Pragmatic Ways to “Hack” the DOM in Model-Driven Apps

Model-Driven Apps (MDAs) in Microsoft Dataverse are powerful, but they are also opinionated. Microsoft intentionally limits direct access to the application shell, global lifecycle events, and certain UI elements.

Despite this, real-world projects often require behavior that goes beyond what is officially supported: hiding global buttons, initializing logic at app startup, or injecting custom UI.

This article describes two practical (but unsupported) techniques to work around these limitations:

  1. Manipulating the DOM after the app loads

  2. Executing JavaScript when the Model-Driven App opens by editing the app XML

Disclaimer
Both techniques rely on undocumented or unsupported behavior. Use them cautiously and expect breaking changes after platform updates.

1. Hacking the DOM After Load (Polling the Shell)

The Problem

Some global UI elements—such as the Quick Create button—cannot be hidden using supported APIs or command bar rules. They exist outside the form context and are rendered dynamically by the application shell.

The Idea

Instead of relying on supported events, we:

  • Inject an HTML web resource

  • Access the top-level document (window.top.document)

  • Poll the DOM until the target element appears

  • Modify or hide it directly

Example: Hiding the Quick Create Button

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Hide Quick Create</title>
    <script>
        (function () {

            function hideQuickCreate() {
                try {
                    const btn = window.top.document.querySelector(
                        "button[data-id='quickCreateLauncher']"
                    );

                    if (btn) {
                        btn.style.display = "none";
                        return true;
                    }
                } catch (e) {
                    console.log(e);
                }
                return false;
            }

            const interval = setInterval(() => {
                if (hideQuickCreate()) {
                    clearInterval(interval);
                }
            }, 500);

        })();
    </script>
</head>
<body></body>
</html>

Why This Works

  • The app shell loads asynchronously

  • The button is injected after initial page load

  • Polling ensures the script runs after the element exists

Risks & Limitations

  • DOM structure and data-id values are not guaranteed

  • Cross-frame access may be blocked in future versions

  • Performance impact if polling is abused

This approach is best suited for small, targeted UI tweaks where no supported alternative exists.

Running JavaScript When a Model-Driven App Loads (Undocumented OnLoad)

The Problem

Model-Driven Apps do not officially expose a global onLoad event like forms do.
There is no supported way to run JavaScript when the app itself opens.

Yet sometimes you need exactly that:

  • Initialize global variables

  • Show notifications

  • Open dialogs or side panels

  • Perform app-level configuration

The Undocumented Solution

Model-Driven Apps internally support event handlers at the app level, configured in the app’s XML definition.

This is not documented—but it works.

What Is a Panel?

A panel is a static side pane that appears across all pages in a Model-Driven App and displays a web page from a URL.

Microsoft officially supports loading panels via:

Xrm.Panel.loadPanel(url, title);

Docs:
https://docs.microsoft.com/en-us/powerapps/developer/model-driven-apps/clientapi/reference/xrm-panel/loadpanel

Triggering Code at App Startup

Step 1: Create a JavaScript Web Resource

Example use case: load a side panel when the app opens.

var MEA = MEA || {};
MEA.Apps = MEA.Apps || {};
MEA.Apps.SalesHub = {
    onLoad: function () {
        Xrm.Panel.loadPanel(
            "https://www.youtube.com/embed/VIDEO_ID",
            "Now Playing"
        );
    }
};

Step 2: Export the Solution

  • Create a solution containing the Model-Driven App

  • Export it as unmanaged

  • Extract the ZIP file

Step 3: Edit customizations.xml

Locate the <AppModule> node and add the following:

<EventHandlers>
  <EventHandler
    eventname="onload"
    functionname="MEA.Apps.SalesHub.onLoad"
    libraryname="mea_/Scripts/SalesHub.js"
    parameters=""
    enable="true" />
</EventHandlers>

This configuration tells the platform to execute your JavaScript function when the Model-Driven App loads.

Step 4: Repack and Import

  • Re-zip the solution files

  • Import the solution back into Dataverse

Once imported, your JavaScript runs automatically at app startup.

Why This Works

Internally, Model-Driven Apps use the same event pipeline as forms.
The platform already supports app-level event handlers—Microsoft just hasn’t documented or officially exposed them.

This behavior was likely inspired by internal features such as Teams Calls integration introduced in Dynamics 365 Sales Wave 1 (2021).

Both approaches demonstrate a common reality in enterprise projects:

Sometimes business requirements move faster than platform features.

  • DOM hacking gives you quick UI control

  • XML-based app onLoad unlocks powerful startup logic