Hello! Welcome back to your advanced Power Platform developer course.
In our last lesson, we focused on implementing Business Process Flows to create guided, structured experiences for users within standard Model-driven App forms. This is a powerful way to enforce a process.
Today, we're taking the next step in UI customization. What if the standard form layout isn't enough? What if you need a completely tailored user experience, a unique layout, or the ability to connect to external services directly from the UI? Your goal for this lesson is to learn how to create custom pages in Model-driven Apps to provide tailored user experiences.
This powerful feature represents the convergence of Model-driven and Canvas apps, allowing you to embed the pixel-perfect design freedom of a Canvas App directly within the structured, data-centric world of a Model-driven App. For someone with your background in classic Dynamics 365 development, this is the modern successor to building complex HTML and JavaScript web resources.
1. The "Why": App Convergence and Declarative UI
Before we jump into building, it's important to understand the paradigm shift that custom pages represent. Historically, creating a bespoke UI in a Model-driven App meant writing imperative code—HTML for structure, CSS for style, and JavaScript for logic and data access. You were responsible for telling the platform how to do everything, from rendering controls to managing data.
Custom pages, being built on the Canvas App engine, embrace a declarative approach using Power Fx. You define what you want the UI to look like and how it should behave, and the platform handles the underlying rendering, performance optimization, and data binding.
How do custom pages change model-driven apps?
To understand this strategic shift, watch this short video from Scott Durow, a well-known architect in the Power Platform space. He explains the concept of app convergence and the move from imperative to declarative programming.
Watch the video from 00:33 to 07:06. Focus on: How custom pages address the need for specific user interfaces that standard forms can't provide. The distinction he makes between imperative (like your classic JS/HTML web resources) and declarative (Power Fx) programming. The benefits of the declarative approach, such as lower total cost of ownership and reduced maintenance.
This shift to a declarative model allows you to build sophisticated UIs faster and more reliably, while still having the power to integrate pro-code components (like PCF controls) where necessary.
2. Building and Integrating Your First Custom Page
Let's get practical. You create and manage custom pages within the context of a solution and the modern app designer. A custom page is, for all intents and purposes, a special type of Canvas App.

We'll now walk through the process of creating a simple, responsive custom page and adding it to a Model-driven App's sitemap.
Getting Started with Model-Driven App Custom Pages and Command Designer in Power Apps
This video from Reza Dorrani provides an excellent, end-to-end demonstration of creating a custom page. We will break it down into key steps.
First, watch from 08:26 to 15:29. This segment covers: Adding a Custom Page: How to add a new custom page from within the Model-driven App designer. Responsive Design: The critical step of using Vertical and Horizontal containers to make the page layout responsive. Pay close attention to how he sets the Width and Height properties to Parent.Width and Parent.Height. Connecting to Data: Adding a Dataverse table (like 'Devices' in his example) as a data source. Displaying Data: Using a gallery to display records from the connected table.
As you saw, responsive design is not automatic; you must be intentional by using layout containers. The Microsoft documentation page, "Design a custom page for your model-driven app," provides excellent recipes for common responsive layouts, such as a fixed header and footer with a flexible body. I recommend keeping this page (LINK) bookmarked for reference.
3. Navigation and Context Passing
A custom page that can't interact with its host Model-driven App is of limited use. Let's explore how to navigate between the custom page and standard MDA forms, and crucially, how to pass context (like a record ID) between them.
Navigating from the Custom Page to the MDA
You can trigger navigation from your custom page to a standard Model-driven App form using the Power Fx Navigate function. You can use it to:
- Open a new record form:
Navigate(Defaults(YourTable)) - Open an existing record form:
Navigate(LookUp(YourTable, ID = recordGuid))orNavigate(gallery.Selected)
Getting Started with Model-Driven App Custom Pages and Command Designer in Power Apps
Let's return to Reza's video to see this in action.
Watch the short clip from 15:29 to 16:46. Notice how he uses the Navigate function on an 'Add' icon to open the new record form and on the gallery's OnSelect property to open the selected record's form.
Navigating from the MDA to the Custom Page
A more common developer scenario is to launch a custom page from a command bar button, often passing the context of the selected record. This requires a combination of JavaScript and Power Fx.
- JavaScript (Command Bar): You use the
Xrm.Navigation.navigateTofunction to open the custom page. You can specify whether it opens as a full page, a centered dialog, or a side pane. - Power Fx (Custom Page): Inside the custom page, you use the
Param()function to read the parameters passed from the JavaScript call.
Getting Started with Model-Driven App Custom Pages and Command Designer in Power Apps
This is a multi-step process. The next segments of the video demonstrate how to wire this up.
Watch from 24:34 to 33:09. This is a developer-focused section that should align well with your C# and JavaScript background. JavaScript Web Resource (24:34 - 28:00): Observe how he creates a JavaScript function that uses Xrm.Navigation.navigateTo to open a custom page as a side dialog. The logical name of the custom page is essential here. Command Bar Configuration (28:00 - 29:20): See how he wires the command bar button to call this new JavaScript function. Receiving Context in Power Fx (29:20 - 33:09): This is the crucial part. Pay close attention to how the custom page's OnStart property uses Param("recordId") to read the ID passed from the command bar. He then uses this ID to filter the gallery and show contextual data.
This pattern of launching a contextual custom page from the command bar is a cornerstone of building tailored user experiences.
Test your understanding!
You have a "Project" table and you want to create a custom page that acts as a "Quick Status Update" dialog. From the Project form's command bar, a user should be able to click a button that opens a centered custom page dialog. This dialog should display the project's name and allow the user to enter a status update note.
Outline the high-level steps to implement this, mentioning the key functions you'd use in both JavaScript and Power Fx.
Show answer
- Create the Custom Page: Design a custom page with a label for the project name and a text input for the status note.
- Create JavaScript Web Resource: Write a function that accepts the
formContextas a parameter. Inside, get the project's ID usingformContext.data.entity.getId(). - Call
navigateTo: UseXrm.Navigation.navigateToin your JavaScript. ThepageInputobject will specify the custom page's name and pass the project ID in therecordIdproperty. ThenavigationOptionswill specifytarget: 2(dialog) andposition: 1(centered). - Configure Command Bar: Add a button to the Project form's command bar. Configure it to run your JavaScript function, passing the
PrimaryControl(which provides theformContext). - Receive Context in Power Fx: In the custom page's
OnStartproperty (or another suitable property), useSet(varProjectId, Param(\"recordId\"))to retrieve the ID. - Display Data: Use
LookUp(Projects, Project = GUID(varProjectId)).'Project Name'to fetch and display the project's name in the label.
4. Advanced Pattern: Two-Way Communication
The standard navigateTo function is great for passing data to a custom page, but it doesn't provide a direct way to get data back when the dialog closes. For complex scenarios like custom approval forms or multi-step wizards, you need a robust callback mechanism.
The following article outlines a professional, reusable pattern to achieve this. It leverages a custom Dataverse table to act as an intermediary for passing data back to the calling JavaScript.
Power Apps Custom Page Dialogs in Model-Driven Apps: Passing & Receiving Data
This article from Krzysztof Mikołajec on dev.to presents an elegant solution to the callback problem. It's a perfect example of a professional development pattern for Power Platform.
Read the article sections from 'Introduction' through 'How to Wire It Up'. Focus on understanding the following four-step pattern: Step 1 (JS - Sending): Instead of just a record ID, you JSON.stringify a more complex object (containing a sessionId, the actual recordId, and other parameters) and pass it in the recordId field. Step 2 (Power Fx - Receiving): The custom page uses ParseJSON(Param("recordId")) to unpack the incoming data. Step 3 (Power Fx - Returning): When the user clicks 'Submit' on the dialog, the page uses Patch() to write a result object (as JSON) to a dedicated custompagescallback table, using the sessionId as the key. Step 4 (JS - Handling): The .then() block of the original navigateTo call triggers a function that queries the custompagescallback table for the record matching the sessionId, retrieves the result, and then acts upon it.
This pattern is highly valuable because it is generic and reusable. You can create a single JavaScript web resource that handles the launching and callback logic for many different custom page dialogs across your application.
Conclusion
In this lesson, you've bridged the gap between Model-driven and Canvas Apps. You learned how to create bespoke user interfaces that integrate seamlessly into the Model-driven App framework, moving beyond the limitations of standard forms.
Key Takeaways:
- Custom pages represent a shift from imperative (JS/HTML) to declarative (Power Fx) UI development, reducing complexity and maintenance.
- They are built using the Canvas designer with a focus on responsive layouts using container controls.
- You can navigate from a custom page to an MDA form using the Power Fx
Navigate()function. - You can launch a custom page from an MDA command bar using the JavaScript
Xrm.Navigation.navigateTofunction, passing context via parameters. - The custom page receives context using the Power Fx
Param()function. - For advanced two-way data binding, you can implement a callback pattern using a temporary Dataverse table to pass data back from the dialog to the calling JavaScript.
Up Next:
In this lesson, we saw the power of using JavaScript to launch and interact with custom pages. In our next session, we will focus on a core developer best practice: how to implement reusable JavaScript web resource libraries to share functions across multiple form scripts. This will help you write more maintainable, scalable, and professional client-side code for your Model-driven Apps.