Integrate Documentation in Model-Driven Apps
During the last Power Atelier, I got asked: “Hey Michael, how do you usually document your Power Platform solutions?”
I said, “I typically use Atlassian Confluence for documentation and Draw.io for architecture diagrams.”
That kicked off a great discussion – and then someone followed up with,
“Those diagrams and visuals are awesome! I’d love to integrate that documentation in my model-driven apps. But how can I do that?”
I thought about it for a moment… and then I had an idea. What if I stored the documentation directly in Dataverse as a table? Then, I could use a custom page to present images and HTML content. I would also leverage modern commands in my model-driven app to display the documentation right from those pages.
Here is a tutorial for you, how this works…
Storing Documentation Information
First, I created a new table called Documentation in my Dataverse solution InfoHub. Here I’m adding all needed columns for my documentation entry. I will need an identifier, a title, an image, a HTML description, and an URL. In detail, I have created these columns:
As you see, I added the column Key as # Autonumber – this serves as my primary key:
I also added all these fields to my Main form:
All in all, this setup took me about five minutes. Now it’s time to improve how this information is presented in my model-driven app.
Custom Page for Presentation
Next, I added a new custom page to my Dataverse solution. This allows me to use pixel-perfect layouts for better presentation of my documentation inside the model-driven app. For the layout, I used the standard Header with footer design template:
Then, I renamed and added some controls. My resulting design looks like this:
For the app logic, I first added some code to the OnSelect trigger of my App:
Here, I defined default colors for my controls and UI. I also set an initial value for a global variable called glbRefreshRequired.
This variable is used in the OnVisible trigger of my page. Here is the code:
If(glbRefreshRequired = true, Select(btnRefresh));
This simple code triggers my btnRefresh button when a refresh is required. The button itself is located in the header of my page:
Finally, I used the OnSelect trigger of btnRefresh button to load the correct record. Here is the code:
// Extract entity and entity id from page parameters
Set(glbETN, Lower(Coalesce(Param("etn"), glbETN, "")));
Set(glbID, GUID(Coalesce(Param("id"), glbID, "")));
// Start refreshing
Set(glbRefresh, true);
// Get active record from the given ID
Set(glbRecord, LookUp(Documentations As item, item.Documentation = glbID));
// Stop refreshing
Set(glbRefresh, false);
To locate the correct record, I first extract the id parameter. This value is used to lookup the right record and store it in a global variable. That makes it easy to bind all my controls to the properties of that record.
For example, my image control is bound to glbRecord.Image.Full, so I can display the full image instead of just a thumbnail.
So good so far.
Document Viewer Integration
Next, I added my custom page to the model-driven app. After that, I started editing the command bar:
I selected the command bar for the Main form:
Since it was my first time editing a command bar. Therefore, I was asked which type of command I wanted to add:
I selected Power Fx (new) to add a button and write my logic directly in Power Fx.
I created a new command called Documentation on the command bar:
Then, I selected Open formula bar and entered the following Power Fx code:
With({
record: LookUp(Documentations As d, d.Key = "DOC-1001")
},
Navigate(
record, // Target Record
{ Page: 'Documentation Viewer'} // Custom page
);
);
Here, I’m using a local variable called record to find the documentation record with the key DOC-1001. Then, I navigate to that record and pass the custom page name as a parameter. That’s all I need to make it work!
Testing
After publishing my app, I tested the whole setup. I opened the Documentations page and switched to the editor – and there it was: my new Documentation command:
When I clicked the button, my model-driven app navigated to my custom page Documentation Viewer, loading the record with the key DOC-1001:
Exactly what I wanted to see! My stored image and URL were displayed perfectly. The HTML content was invisible – simply because I hadn’t added any yet.
Summary
Today, I demonstrated how to integrate documentation into model-driven apps, making diagrams, HTML content, and URLs easily accessible. I also used modern commands to navigate to a custom page and dynamically load the right record.
First, I created a Dataverse table to store the documentation content and added a custom page for a pixel-perfect presentation. Then, I implemented Power Fx logic to refresh and load records and connected everything to the app’s command bar. The command uses the record key, which can also be defined as an environment variable for a generic setup. As a result, the documentation opens directly from a model-driven app command as part of the app.
In just a few minutes, I can now display rich documentation directly within my apps. Sharing architecture insights, organizational charts, or business process documentation is simplified. In other words, my users can access this directly from my model-driven app.













