Tutorials/Power Apps/Add a Custom Page Modal Dialog to Your Model-Driven App
Power Appsintermediate

Add a Custom Page Modal Dialog to Your Model-Driven App

Learn how to build a modal input dialog using Power Apps custom pages, letting users edit a field on a form without navigating away from the model-driven app context.

NA
Narmer Abader
@narmer · Published June 3, 2026

Custom pages in Power Apps let you embed canvas app functionality directly into a model-driven app. One common need is a modal dialog that appears on top of a form to collect or display extra information. In this article, you’ll learn how to create such a dialog with a custom page, wire it to a Dataverse record, and trigger it from a command bar button using a small JavaScript snippet.

Scenario: Quick Resolution Notes for Support Tickets

Consider a help desk app built on Dataverse. Agents work on Customer Issues records and need to update the Resolution Notes field. Instead of navigating to another tab or form, they can click a toolbar button, enter the notes in a pop-up dialog, and save – all while staying on the same record.

The custom page will:

  • Receive the current issue’s unique ID from the model-driven app.
  • Load the record and display the existing resolution notes.
  • Provide a text input for editing and two buttons (OK and Cancel).
  • Save changes and close the dialog on OK, or simply close on Cancel.

Building the Custom Page

Start inside your model-driven app solution. From the maker portal, edit the app in the modern designer.

1. Add a Custom Page

Click Add Page, select Custom page, then choose Create new custom page. Give it a name like ResolutionDialog. After creation, the custom page opens in the canvas designer.

2. Adjust Display Settings

A custom page normally opens full‑screen. To make it a small dialog, set the following in the Advanced Settings > Display:

  • Width: 600
  • Height: 300
  • Scale to fit: off

Also change the screen’s MinScreenWidth and MinScreenHeight to 200 so it stays compact on smaller devices.

3. Capture the Record ID from the URL

The model-driven app will pass the record ID as a query parameter (?recordId={GUID}). Add the following code to the App object’s OnStart property. It strips the curly braces and converts the value to a GUID, then fetches the record.

Set(
    gblRecordId,
    GUID(
        Mid(
            Param("recordId"),
            2,
            Len(Param("recordId")) - 2
        )
    )
);
Set(
    gblRecordData,
    LookUp(
        'Customer Issues',
        'Customer Issue' = gblRecordId
    )
)

Make sure the Customer Issues table is added as a data source (via the Data pane).

4. Design the Modal Layout

Add a Vertical container as the main holder. Set its X and Y to 0, Width to Parent.Width, and Height to Parent.Height. Use these layout properties:

  • LayoutJustifyContent: LayoutJustifyContent.Start
  • LayoutAlignItems: LayoutAlignItems.Stretch

Inside the container, add a Text input (modern control). Set its Value property to display the current resolution notes when the app is in Play mode:

gblRecordData.ResolutionNotes

Ensure the text input’s Align in container is “Set by container” so it stretches to fill available space.

5. Add OK and Cancel Buttons

Below the text input, add a Horizontal container for the buttons. Set its Justify to End and Align to Top.

Add a button labeled OK. In its OnSelect, save the text input value back to the record and close the dialog:

Patch(
    'Customer Issues',
    gblRecordData,
    {ResolutionNotes: ResolutionInput.Text}
);
Back()

Add a second button labeled Cancel. Its OnSelect simply closes the dialog without saving:

Back()

Save and publish the custom page, then close the canvas designer.

Connecting the Model-Driven Form

Now you’ll add a command bar button that opens the custom page as a modal dialog.

6. Edit the Form Command Bar

In the model‑driven app designer, find the Customer Issues table. Click the three dots next to it and select Edit command bar. Choose Main form.

In the ribbon designer, click New > Command. Give the command a label (e.g., “Update Resolution”) and pick an icon.

7. Add a JavaScript Web Resource

Set the Action dropdown to Run JavaScript, then click Add Library. Choose New web resource and create a JavaScript file (extension .js). Name it something like crXXX_openResolutionDialog.js.

Replace the placeholder content with the code below. Update the name property to your custom page’s logical name (found in the Default Solution under Pages – look for the Name column).

function openResolutionDialog(primaryControl, firstSelectedItemId, selectedEntityTypeName) {
    var pageInput = {
        pageType: "custom",
        name: "crXXX_resolutiondialog_XXXXX", // Replace with your custom page logical name
        entityName: selectedEntityTypeName,
        recordId: firstSelectedItemId
    };
    var navigationOptions = {
        target: 2,
        position: 1,
        height: { value: 260, unit: "px" },
        width: { value: 50, unit: "%" },
        title: "Update Resolution Notes"
    };
    Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(
        function () {
            primaryControl.data.refresh();
        }
    ).catch(
        function (error) {
            console.error(error);
        }
    );
}

Save and publish the web resource. Back in the command properties, select the function openResolutionDialog and map the required parameters (firstSelectedItemId and selectedEntityTypeName – the designer usually provides them). Save the command and publish the model‑driven app.

Security & Performance Considerations

  • Data access – The custom page runs under the current user’s identity. Dataverse roles and privileges apply automatically to LookUp and Patch operations.
  • Performance – Keep the custom page lightweight. Avoid heavy formulas and complex controls inside the modal to ensure it opens quickly.
  • DelegationLookUp is delegable for exact match lookups by GUID; no delegation issues here because you’re filtering on the primary key.

Common Mistakes & Troubleshooting

ProblemLikely CauseSolution
Dialog doesn’t openWrong logical name in pageInput.nameDouble‑check the custom page’s logical name in the solution’s Pages list.
“Record not found” errorTable not added as a data source in the custom pageOpen the custom page and add the table via the Data pane.
Curly braces remain in the GUIDParam("recordId") not properly parsedVerify the Mid formula in OnStart – it should strip the first and last characters.
Form doesn’t refresh after closingMissing primaryControl.data.refresh() or promise not executedEnsure the then callback contains the refresh call.

Final Recommendation

Custom page modal dialogs are a powerful way to keep users inside the context of a model-driven form while providing focused, transactional input. The pattern works for any scenario where you need a simple pop‑up: editing a single field, confirming an action, or displaying extra details. Keep the dialog small, the code clean, and always test with a variety of screen sizes.

References