Power Apps  

Visualizing HTML Changes in Power Apps with a Custom React PCF Control

Introduction

Modern applications demand intuitive ways to visualize differences between versions of data—especially in content management or approval systems. When working with Power Apps and the Power Platform, PowerApps Component Framework (PCF) controls allow us to extend UI capabilities beyond what's natively offered.

In this article, we will walk through the creation of a custom PCF control using React and a powerful HTML diff algorithm. The control visually highlights changes between two versions of HTML content, making it easier for end users to spot modifications.

Use Case: Why Visual HTML Diffs?

  • Content Approval Workflows
  • Audit and Version Control in CRM
  • Email or Webpage Content Review

Being able to see what changed with green inserts and red deletions significantly enhances user experience and productivity.

Tech Stack Used

  • PowerApps Component Framework (PCF)
  • React + TypeScript
  • Custom JavaScript-based HTML diff algorithm

Overview of Components

  • HtmlDiffModule.ts: A custom diff engine that tokenizes HTML, computes diffs, and renders them with semantic <ins> and <del> tags.
  • HtmlDiffControl.tsx: A React component that uses the diff engine and renders the output.
  • HtmlDiffPCFControl.ts: PCF entry point that hooks into the framework lifecycle and renders the React component.

1. Creating the Diff Engine (HtmlDiffModule.ts)

We created a standalone HTML diff engine inspired by Google's htmldiff.js, rewritten in ES module format and adapted for TypeScript.

export function htmldiff(beforeHtml: string, afterHtml: string): string {
  // Implementation uses tokenization and semantic tagging
  // Output uses <ins> for inserts and <del> for deletions
}

2. React Component for Display (HtmlDiffControl.tsx)

import React from 'react';
import { htmldiff } from '../utils/HtmlDiffModule';

interface Props {
  originalHtml: string;
  updatedHtml: string;
}

const HtmlDiffControl: React.FC<Props> = ({ originalHtml, updatedHtml }) => {
  const diff = htmldiff(originalHtml, updatedHtml);
  return (
    <div
      style={{ fontFamily: 'Segoe UI', padding: '1rem' }}
      dangerouslySetInnerHTML={{ __html: diff }}
    />
  );
};

export default HtmlDiffControl;

3. Integrating into PCF (HtmlDiffPCFControl.ts)

import { IInputs, IOutputs } from "./generated/ManifestTypes";
import * as React from "react";
import * as ReactDOM from "react-dom";
import HtmlDiffControl from "./components/HtmlDiffControl";

export class HtmlDiffPCFControl implements ComponentFramework.StandardControl<IInputs, IOutputs> {
  private _container: HTMLDivElement;

  public init(context, notifyOutputChanged, state, container): void {
    this._container = container;
  }

  public updateView(context): void {
    const props = {
      originalHtml: context.parameters.originalHtml.raw || "",
      updatedHtml: context.parameters.updatedHtml.raw || ""
    };
    ReactDOM.render(React.createElement(HtmlDiffControl, props), this._container);
  }

  public getOutputs(): IOutputs {
    return {};
  }

  public destroy(): void {
    ReactDOM.unmountComponentAtNode(this._container);
  }
}

4. Manifest File Configuration (ControlManifest.Input.xml)

Define your string parameters to receive the original and updated HTML:

<property name="originalHtml" type="SingleLine.Text" usage="bound" />
<property name="updatedHtml" type="SingleLine.Text" usage="bound" />

Output Example

The resulting control renders HTML with:

  • Green-highlighted <ins> for added content
  • Red-strike <del> for deleted content

This format is intuitive and helpful for both business users and developers.

Where to Use This

  • Embed in Model-Driven Apps
  • Reuse in Canvas Apps with component libraries
  • Plug into CRM audit fields or custom portals

Conclusion

This custom PCF control showcases how you can enhance Power Apps using React and smart algorithms. By abstracting the comparison logic into a standalone module, it remains reusable, testable, and scalable.

Would love to hear your feedback and how you might use this in your organization!