Custom Events in PCF Components

 

Introduction

In modern low-code development, Power Apps Component Framework (PCF) plays a vital role in enhancing the user interface and delivering rich interactive components. As part of building truly dynamic PCF components, one powerful capability is the event mechanism—especially custom events that allow developers to trigger and listen to component-specific behavior across the app.

In this post, we'll explore how PCF components handle events, including how to raise and handle custom events. We’ll also look at practical use cases, implementation steps.

 

What Are Events in PCF?

Events in PCF enable components to communicate with the model-driven app form or other consumers of the control. Microsoft introduced support for custom event handling, allowing PCF control to:

  • Raise events from within the control (e.g., on button click).
  • Notify the hosting form or script when something changes in the control.
  • Enable loosely coupled communication between PCF and form JavaScript.

This makes your components not just reusable—but also responsive and context-aware.

 

Types of Events

In PCF, you can deal with:

  1. Standard events – such as notifyOutputChanged() to let the platform know output properties have changed.
  2. Custom events – defined and raised by the developer for more granular control.

We’ll focus on custom events here.

 

Why Use Custom Events in PCF?

Some real-world scenarios where custom events make sense:

  • A multi-select dropdown PCF control where you want to fire a form-level alert when a specific value is chosen.
  • A file uploader control where form logic should be triggered after file validation succeeds.

 

What We’ll Build

The steps will guide you to create a code component with two buttons which raise different events for the hosting application can react to. You'll define two events: customEvent1 and customEvent2. Then, the code component exposes two buttons that cause these events to occur.

 

Prerequisites

Before starting, ensure you have:

  • Power Apps CLI installed
  • Node.js and NPM.
  • A Dataverse environment.
  • Visual Studio Code.

 

Create a new control:

1.      Create a new component using similar command. –

pac pcf init -ns Mahesh -n CustomEventForPCF -t field -fw react -npm

2.      Edit the Manifest file to add the new events

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<manifest>
  <control namespace="Mahesh" constructor="CustomEventForPCF" version="0.0.2" display-name-key="CustomEventForPCF" description-key="CustomEventForPCF description" control-type="virtual" api-version="1.3.18">
    <property name="sampleProperty" display-name-key="Button Label" description-key="Enter a label for button" of-type="SingleLine.Text" usage="bound" required="true"/>
    <event name="customEvent1" display-name-key="customEvent1" description-key="customEvent1"/>
    <event name="customEvent2" display-name-key="customEvent2" description-key="customEvent2"/>
    <resources>
      <code path="bundle.js" order="1"/>
      <platform-library name="React" version="16.14.0"/>
      <platform-library name="Fluent" version="9.46.2"/>
    </resources>
    <feature-usage/>
    <built-by name="pac" version="1.46.1"/>
  </control>
</manifest>

 

Define events:

Rename the HelloWorld.tsx file and define two events in the interface and bind the events to two different buttons. Also update the import to include DefaultButton as below.

import * as React from 'react';
import { Label, DefaultButton } from '@fluentui/react';


export interface IButtonProps {
  onCustomEvent1: () => void;
  onCustomEvent2: () => void;
}

export class Button extends React.Component<IButtonProps> {
  public render(): React.ReactNode {
    return (
      <>
      <Label>PCF Control with Event</Label>
      <DefaultButton onClick={this.props.onCustomEvent1}>Trigger event 1</DefaultButton>
      <DefaultButton onClick={this.props.onCustomEvent2}>Trigger event 2</DefaultButton>
      </>
    )
  }
}

 

Modify updateView method:

In Index.ts, modify the updateView method to add handlers for the two button events. These handlers add the two events defined in the manifest to the events in the context passed to the control.

import { IInputs, IOutputs } from "./generated/ManifestTypes";
import { Button, IButtonProps } from "./Buttons";
import * as React from "react";

export class CustomEventForPCF implements ComponentFramework.ReactControl<IInputs, IOutputs> {
    private notifyOutputChanged: () => void;

    /**
     * Empty constructor.
     */
    constructor() {
        // Empty
    }

    /**
     * Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
     * Data-set values are not initialized here, use updateView.
     * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
     * @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
     * @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
     */
    public init(
        context: ComponentFramework.Context<IInputs>,
        notifyOutputChanged: () => void,
        state: ComponentFramework.Dictionary
    ): void {
        this.notifyOutputChanged = notifyOutputChanged;
    }

    /**
     * Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
     * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
     * @returns ReactElement root react element for the control
     */
    public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
        const props: IButtonProps = {onCustomEvent1: ()=> {context.events?.customEvent1()}, onCustomEvent2: () => {context.events?.customEvent2()}};
        return React.createElement(
            Button, props
        );
    }

    /**
     * It is called by the framework prior to a control receiving new data.
     * @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as "bound" or "output"
     */
    public getOutputs(): IOutputs {
        return { };
    }

    /**
     * Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
     * i.e. cancelling any pending remote calls, removing listeners, etc.
     */
    public destroy(): void {
        // Add code to cleanup control if necessary
    }
}

 

Build and package

As usual, you need to complete these steps to use this control:

  1. Create and build the code component
  2. Package the code component
  3. Deploy the code component

 

Use in a Model-Driven app:

1.      Create a new JavaScript web resource to run on the onLoad event of a form. This script binds two event handlers to the new events for the controls on load of the form.

var Mahesh = Mahesh || {};

Mahesh.ContactForm={

    onLoad: function(exeContext){
        Mahesh.ContactForm.addEventHandlerOnPCFCustomEvent(exeContext);
    },

    addEventHandlerOnPCFCustomEvent : function(exeContext){
        const formContext = exeContext.getFormContext();
        const sampleControl1 = formContext.getControl("new_pcffield");
        sampleControl1.addEventHandler("customEvent1", Mahesh.ContactForm.onSampleControl1CustomEvent1);
        sampleControl1.addEventHandler("customEvent2", Mahesh.ContactForm.onSampleControl1CustomEvent2);
    },

    onSampleControl1CustomEvent1: function(exeContext){
        alert(`SampleControl1 Custom Event 1`);
    },

    onSampleControl1CustomEvent2: function(exeContext){
        alert(`SampleControl1 Custom Event 2`);
    }

}

2.      Configure the onload event as shown in the following image:

 



3.      When you navigate to the form and press Trigger event 1, an alert displays SampleControl1 Custom Event 1. When you press Trigger event 2, an alert displays SampleControl1 Custom Event 2. 

 








Similarly, you can also pass Payload along with the Custom Event: Tutorial: Define a custom event in a component - Power Apps | Microsoft Learn

 

You will also be able to call these Custom Events in Canvas apps: Tutorial: Define a custom event in a component - Power Apps | Microsoft Learn


 

 Relates Articles:

Define Events (preview) - Power Apps | Microsoft Learn

Tutorial: Define a custom event in a component - Power Apps | Microsoft Learn

 

 

 

 

Comments

Popular posts from this blog

Dataverse Native Git Integration

Set up Power Platform Managed Identities for Dataverse Plugins