Skip to Content

Build a Reusable PCF Dialog Framework for Dynamics 365

One shared helper to open any Custom Page as a modal — less code, consistent dialogs, one place to maintain.
31 July 2026 by
Build a Reusable PCF Dialog Framework for Dynamics 365

If you open Custom Page modals from many places in your Dynamics 365 app, you quickly notice a problem: the same JavaScript gets copied again and again, each button hard-codes its own page name and sizes, and one small change means editing a dozen web resources. The fix is a reusable PCF dialog framework — a single, well-designed layer that opens any Custom Page as a modal with consistent behavior.

This article — part of our series on hosting PCF controls in modal popups — shows you how to build that framework step by step, in plain language.

Why You Need a Framework

Without a shared layer, every dialog is a one-off. That leads to duplicated code, inconsistent dialog sizes, and no single place to add logging, error handling, or a loading state. A framework solves all of this by giving you one function to open any dialog and one place to change behavior.

  • Consistency — every dialog looks and behaves the same.
  • Less code — buttons just say “open this page with this record.”
  • Easy maintenance — change sizing or error handling in one file.
  • Reusability — new dialogs need almost no new code.

The Core Idea

The framework is a single helper (a JavaScript web resource) that wraps Xrm.Navigation.navigateTo(). Every ribbon button calls the helper with a small options object instead of writing its own navigation code.

// cloudverve_dialogFramework.js  — one shared web resource
var CloudVerve = window.CloudVerve || {};
CloudVerve.Dialog = (function () {

    function open(config, primaryControl) {
        var ctx = primaryControl;
        var recordId = config.recordId ||
            (ctx && ctx.data.entity.getId().replace(/[{}]/g, ""));
        var entityName = config.entityName ||
            (ctx && ctx.data.entity.getEntityName());

        var pageInput = {
            pageType: "custom",
            name: config.pageName,          // logical name of the Custom Page
            recordId: recordId,
            entityName: entityName
        };

        var options = {
            target: 2,                      // modal dialog
            position: config.position || 1, // center by default
            width:  config.width  || { value: 60, unit: "%" },
            height: config.height || { value: 70, unit: "%" },
            title:  config.title  || "Dialog"
        };

        return Xrm.Navigation.navigateTo(pageInput, options).then(
            function () { if (config.onClose) config.onClose(ctx); },
            function (e) { CloudVerve.Dialog._error(e); }
        );
    }

    return {
        open: open,
        _error: function (e) { console.error("[CloudVerve.Dialog]", e); }
    };
})();

Calling the Framework from a Button

Now any ribbon button is a one-liner. It describes what to open, not how:

function openCustomer360(primaryControl) {
    CloudVerve.Dialog.open({
        pageName: "cr123_customer360_page",
        title: "Customer 360",
        width:  { value: 70, unit: "%" },
        height: { value: 80, unit: "%" },
        onClose: function (ctx) { ctx.data.refresh(false); }
    }, primaryControl);
}

Every dialog in your app now flows through the same code path — so sizing, titles, error handling, and the post-close refresh are all consistent.

Developer building a reusable dialog framework in an IDE
One shared helper opens every Custom Page dialog with consistent behavior.

Adding Shared Features

Because everything runs through one function, you can add powerful features in a single place and every dialog gets them for free:

  • Standard sizes — small, medium, large presets instead of magic numbers.
  • Loading indicators — show a spinner while the page loads.
  • Central error handling — one place to log and show friendly messages.
  • Telemetry — track which dialogs are used and how often.
  • Auto-refresh — refresh the parent form or a named subgrid on close.

Best Practices

  • Keep the framework in one web resource and version it carefully.
  • Use named size presets so dialogs stay visually consistent.
  • Always pass only the data the page needs.
  • Handle the no-record case (dialogs opened from a grid or the nav bar).
  • Document the config options so any developer can add a dialog.

Conclusion

A reusable PCF dialog framework turns dozens of copy-pasted scripts into a single, reliable helper. You write less code, ship consistent dialogs, and gain one place to improve every popup at once. It’s the foundation that makes the rest of this series — passing data, AI panels, multi-dialog flows, and wizards — simple to build.

Related: start with the cornerstone guide, How to Open a PCF Control in a Modal Popup Using Custom Pages in Dynamics 365.

Want a production-ready dialog framework for your model-driven apps? Talk to the CloudVerve team.