A modal popup is only useful if the component inside it knows what it’s working on. When you open a Custom Page that hosts a PCF control, you need to get data into the page (which record, which user, what mode) and often get results back out when the user is done. Getting this data flow right is what makes the whole pattern feel seamless.
This guide — part of our series on hosting PCF controls in modal popups — explains, in simple terms, how to pass data between Custom Pages and PCF controls in both directions.
The Three Hops of Data
Data travels through three stages. Understanding these makes everything else click:
- JavaScript → Custom Page: you send values in the
navigateTocall. - Custom Page → PCF control: Power Fx reads those values and binds them to the control’s input properties.
- PCF control → Dataverse (and back): the control reads/writes data and can signal the page when it’s finished.
Step 1 – Send Data When Opening the Page
The navigateTo call carries the context. Along with recordId and entityName, you can pass a custom JSON payload as a string:
var pageInput = {
pageType: "custom",
name: "cr123_editcustomer_page",
recordId: recordId,
entityName: "account",
// extra data as a JSON string
data: JSON.stringify({ mode: "edit", userId: Xrm.Utility.getGlobalContext().userSettings.userId })
};
Xrm.Navigation.navigateTo(pageInput, { target: 2, width: {value:60,unit:"%"} });
Step 2 – Read the Data in the Custom Page
Inside the Custom Page, Power Fx exposes what you passed through the Param() function. Read it in the page’s OnStart or OnVisible and store it in variables:
// Power Fx — App.OnStart or Screen.OnVisible
Set(gRecordId, Param("recordId"));
Set(gEntity, Param("entityName"));
Set(gPayload, Param("data")); // JSON string you sent
Tip: Param() always returns text, so convert numbers or booleans as needed, and treat missing values with a default.
Step 3 – Pass Data into the PCF Control
Select the PCF control on the page and bind its input properties to your variables in Power Fx. For example, set the control’s RecordId property to gRecordId and a Config property to gPayload. Inside the control, you read them from context:
// PCF — index.ts
public updateView(context: ComponentFramework.Context<IInputs>): void {
const recordId = context.parameters.RecordId.raw ?? "";
const config = JSON.parse(context.parameters.Config.raw ?? "{}");
// now render using recordId + config
}
Step 4 – Send Data Back Out of the Control
When the user finishes, the PCF control raises an output property and calls notifyOutputChanged(). The Custom Page reacts to that change — for example, saving with Patch() or closing with Back():
// PCF — raise a result the page can read
this._result = JSON.stringify({ status: "saved", id: newId });
this._notifyOutputChanged();
public getOutputs(): IOutputs { return { Result: this._result }; }
On the Custom Page, the control’s OnChange reads Self.Result and acts on it — then Back() closes the modal and returns control to the form.
Common Pitfalls
- Everything is text.
Param()returns strings; parse JSON and convert types. - Payload too big. Pass IDs and let the control fetch details from Dataverse.
- Timing. Read parameters in
OnStart/OnVisible, not before the page loads. - Output not firing. You must call
notifyOutputChanged()for the page to see a result.
Conclusion
Passing data between Custom Pages and PCF controls comes down to three clean hops: send it in navigateTo, read it with Param(), and bind it to the control — then send results back with an output property. Master this flow and your modal dialogs become fully interactive, two-way experiences.
Related: Open a PCF Control in a Modal Popup Using Custom Pages. Need help wiring complex data flows? Talk to the CloudVerve team.