Power Apps Grid Control – First Glimpse to the Cell Renderer and Editors

We’ve saw the Power Apps grid control (Preview) in the latest Wave Announcements. Each time we hear about great improvements. In Release Wave 1/2022 we’ve got inline-editing and infinite scrolling. But as we’ve tried it out, we saw the last parameter which sounded really promising:

The description of the parameter was really exciting:

Full logical name of the control (…) that provides custom cell renders and/or editors for the Power Apps grid control

The description was confirmed in the Release Wave 2/2022 :

Customizable cells: If the default visualization for the cells in one or more columns doesn’t meet your needs, makers can create custom cell renderers and editors to modify how cells look when showing data and when users are editing data.

Since yesterday we can find in the docs how the control works. And there is also an example in the github Power-Apps-Samples. Of course I had to try it out :-). Please remember that this is a preview, and shouldn’t be used in production for now.

Why is this control better than a dataset PCF?

Of course, we were able to make a dataset PCF before too. And there are a lot of cases where a Dataset PCF is still the best choice. But if we only want to change one or two columns, the implementation effort is pretty big. I’ve wrote several blogs about the difficulties of implementing a dataset PCF. And even after solving a lot of problems, there are some features (like implementing the column filter) where the effort is just too big compared with the advantage of having just one column rendered different.

The Power Apps Grid Control offers us a light-weight way, to have the best of both worlds.

Here is the example of the implementation of ColorfulOptionset Grid using a Power Apps Grid control: full editable and having all the goodies

For a short demo, have a look to this video:

How it renders?

First the whole Power Apps Grid will be rendered. Including the columns where you’ve defined your own renderer. After that the “init” method of your PCF will be called, and then your control renderer will be applied/shown. Usually it doesn’t take that long until the final rendering is done, but sometimes it could be a little delay there, so the user might see that change too.

The complete code for this examples is available on my GitHub: https://github.com/brasov2de/GridCustomizerControl/tree/main/CellRenderer

Is this control a PCF?

Yes, kind of. The Power Apps Grid Control is developed and deployed inside a PCF. Which is great because we can (re)use the same knowledge we have already. By using the PCF we can deploy code components, use also external libraries which are bundled together with the control, deploy CSS, declare the feature-usage like webAPI, utilities or some device features.

If the PCF is of type “virtual”, we can also use of the Platform own React and FluentUI.

But it is a special PCF!

Let’s see how it’s different:

The manifest

The Power Apps Grid Control manifest doesn’t look different that a classic PCF. Except that there is only one property: “EventName”. We cannot define anything in the customizing; this property is used by the platform to pass an event name where we can attach to.

<property name="EventName" 
      display-name-key="Property_Display_Key" description-key="Property_Desc_Key" 
      required="true" />


Inside the index.ts we have a “ComponentFramework.ReactControl” with the known methods: init, updateView, getOutputs, destroy. But we actually use only the “init”.

The updateView is called too, but the ReactElement we return there is rendered hidden somewhere in the DOM. We won’t get to see it. So it’s enough to return there an empty react fragment:

    public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
        return React.createElement(React.Fragment);

The getOutputs won’t be used nether. This is not the way we communicate with the platform, it’s not the way we send the changes.

This PCF is not a control that will be rendered in each cell of the grid. We can register only one control per Power Apps Grid, and I see it more like a wrapper for the cell renderer.

The magic happens inside the “init” method. There we can fire an event, which will be process by the Grid. Here is where the “EventName” comes into play. The platform tells us this way, which event should be triggered.

public init(
     context: ComponentFramework.Context<IInputs>,
     notifyOutputChanged: () => void,
      state: ComponentFramework.Dictionary
 ): void {
     const eventName = context.parameters.EventName.raw;
     if (eventName) {
         //this describes the cell renderer for read-only or editable mode.
         const paOneGridCustomizer: PAOneGridCustomizer = { 
         //seems that the context.factory has a "fireEvent" method 
         //which is not documented yet
         (context as any).factory.fireEvent(eventName, paOneGridCustomizer);

The EventName will be different each time:

The cell renderer

The TypeScript types are provided in the template from the Power Apps Samples

 * Provide cell renderer overrides per column data type.
export type CellRendererOverrides = {
  [dataType in ColumnDataType]?: 
     (props: CellRendererProps, rendererParams: GetRendererParams) 
        => React.ReactElement | null | undefined;

An example for a cell renderer could look like this:

//for each date type we can provide a renderer
const cellRendererOverrides: CellRendererOverrides = {
   ["Text"]: (props: CellRendererProps, rendererParams: GetRendererParams) => {          
      //if it returns null, the default Power Apps Grid renderer will be used  
      return null;
    ["OptionSet"]: (props: CellRendererProps, rendererParams: GetRendererParams) => {    
       //now all OptionSet columns will be rendered with Icons and labels                
       return (<div>
          <Icon style={{color: "red"}} iconName="CircleShapeSolid" aria-hidden="true" /> 
     ["TwoOptions"]: (props: CellRendererProps, rendererParams: GetRendererParams) => {     
        const column = rendererParams.colDefs[rendererParams.columnIndex];             
           //in this case I want to change only a specific column
           const smiley = props.value === "1" ? "Emoji2" : "Sad";
           const label = props.formattedValue;             
           return <div style={{textAlign: "center"}}><Icon iconName={smiley}></Icon></div>

When we implement a cell renderer, the props contains information about the cell data, while the rendererParams information about the columns/rowData. Here is an extract

   columnDataType: "TwoOptions",
   columnEditable: true,
   value: "1",
   formattedValue: "Happy", 
   rowHeight: 42
   colDefs: [
         name: "diana_ishappy",
         dataType: "TwoOptions",
         displayName: "Is Happy", 
         editable: true,
         isPrimary: false,
         isRequired: false,
         sortDirection: -1 , 
         width : 100     
         name: "diana_technologycode",
         displayName: "Technology Code", 
         editable: true,
         isPrimary: false,
         isRequired: false,
         sortDirection: -1, 
   rowData: {
      __rec_id: "3cb517f8-2960-ec11-8f8f-000d3aa823b8",
      //... the other attributes

The “rowData” provides the id (“__rec_id”). I’m not so sure about the format of the other values. Booleans are “1”, optionsetcode is as string, but multioptionset is an array of numbers. But it’s a preview, so I’m sure if will get better.

The cell editor

The types for a cell editor looks like this

 * Provide cell editor overrides per column data type.
export type CellEditorOverrides = {
  [dataType in ColumnDataType]?: 
    (defaultProps: CellEditorProps, rendererParams: GetEditorParams)
    => React.ReactElement | null | undefined;

The defaultProps has less data that the cell renderer. For instance there is no “formattedValue”

The rendererParams are similar to the ones from the cell renderer: has colDefs, rowData, and a few more.

When is the editor triggered

In my test, the cell editor was triggered if I didn’t have a cell renderer for that data type. For instance, for “Text” my cell renderer returned null. In that case, the cell editor was called automatically when I’ve clicked on a text cell and entered the edit mode.

For OptionSet or Booleans, I had already an own cell renderer, and the cell editor was not called automatically. In order to make it work, I had to use the props provided for the cell renderer: there is a “startEditing” method, which activated my cell editor code.

(props: CellRendererProps, rendererParams: GetRendererParams) => {            
    const onCellClicked = (event?: React.MouseEvent<HTMLElement, MouseEvent> | MouseEvent) => {
       if(props.startEditing) props.startEditing();               
    return (<div onClick={onCellClicked}>
       <Icon iconName="CircleShapeSolid"/> 

Implementing the editor

The implementation of the editor is a little challenging. We don’t get the formattedValues in the defaultProps. We also need to show all the options in the DropDown. I’ve found them only in a property which not documented in the types: customizerParams.

When the value changes, we need to notify the Grid. We can do that with a method from the rendererParams: onCellValueChanged.

If we want to leave the edit mode after a value was changed, we have also a “stopEditing” method. This one will set the Grid row in a “non-edit” mode.

Here is the code for my ColorfulOptionSet editor:

 ["OptionSet"]: (defaultProps: CellEditorProps, rendererParams: GetEditorParams) => {
      const defaultValue = defaultProps.value as number;
      //get the cell and the options
      const cell = rendererParams.colDefs[rendererParams.columnIndex];  
      const options =  (cell as any).customizerParams.dropDownOptions.map((option:any) => { 
        return {
          ...option, data: {color: colors[option.key]}

      //when the value changes, we notify the Power Apps Grid 
      //by using "onCellValueChanged"
      const onChange=(value: number | null) =>{
      //I've created a react component ColorfulDropDown in a separate tsx file. 
     // You can find it in my repository
      return <ColorfulDropDown defaultValue={defaultValue} options = {options} onChange={onChange}/>

A similar challenge was to get the labels for the Boolean control; I’ve found them only inside the not documented “customizerParams”:

 const column = rendererParams.colDefs[rendererParams.columnIndex];
 const value  = defaultProps.value as string === "1" ? false : true; 

 const label = value === true 
              ? (column as any).customizerParams.labels.onText 
              : (column as any).customizerParams.labels.offText;

Recap for cell renderer and editor

  • inside the renderer: (props: CellRendererProps, rendererParams: GetRendererParams) =>
    • props.value & props.formattedValue
    • props.startEditing()
  • inside the editor: (defaultProps: CellEditorProps, rendererParams: GetEditorParams) =>
    • rendererParams
    • rendererParams.onCellValueChanged(newValue);
    • rendererParams.stopEditing(cancel?: boolean)
  • in both renderer and editor
    • column = rendererParams.colDefs[rendererParams.columnIndex]
    • data = rendererParams.rowData

With these ones I could make my control work. It doesn’t mean these are the best. Maybe I should add defaultProps.onChange method (but somehow it didn’t work properly for me). And an interesting CellRendererProps.onCellClicked (found in the types.ts but not in my environment). Maybe we’ll find out later if there is a better way. Let’s see.

When you need extended data

[Edit] I’ve realized later, that the colors for the OptionSets were actually delivered by the platform, if I would have configured the Power Apps Grid to retrieve the colors (an option in the cvustomizations of the Power Apps Grid). But the colors for Booleans are not retrieved. So I still let this part of the blog here, because it could be useful for booleans or other kind of metadata needed.

As I’ve mentioned, I’ve found the options for an OptionSet inside the column.customizerParams”. Unfortunately, even there the color for the Options was missing

To solve that problem, I’ve retrieved the metadata first, and when the Promise was resolved, I’ve defined the renderer and the editors inside a closure which had access to my colors. The changed code for my “init” method:

context.utils.getEntityMetadata("diana_pcftester", ["diana_technologycode"]).then((metadata)=>{
   const options = metadata.Attributes.get("diana_technologycode")?.attributeDescriptor.OptionSet as Array<any>|null|undefined;          
   const colors = options?.reduce((prev, current)=>{
      return {...prev, [current.Value] : current.Color}
    }, {}) ?? {};          

    if (eventName) {
       const paOneGridCustomizer: PAOneGridCustomizer = { 
          cellRendererOverrides: generateCellRendererOverrides(colors), 
          cellEditorOverrides : generateCellEditorOverrides(colors)
       (context as any).factory.fireEvent(eventName, paOneGridCustomizer); 

//for instance the generateCellRenderer looks like this
export const generateCellEditorOverrides = (colors : any)=>{
   const cellEditorOverrides= {....}
    return cellEditorOverrides;

Final thoughts

…this is huge! A game changer

I’m sure this is just the beginning. There are a lot of aspects I didn’t covered. But even so we can see that the value added to the mode-driven apps is huge. I’m looking forward to find how much more is possible to archieve.

…but I’m hoping for some improvements

How generic are these controls? When we develop PCFs, we are used to think generic; they have parameters which can be defined in customizing. The Power Apps Grid control though, has no way to define any kind of customization. If I want to show an icon in a control, I need to hard-code it. If the same control can be used somewhere else, but with another icon, I need to make another control.

I’m sure there are ways to archieve some generic levels. For instance by defining a EnvironmentVariable, which can be read by the control. Somehow the control must know which configuration should be used. I wish there was another parameter to the Power Apps Grid, where we can pass a JSON configuration to the control.

Another issue might be the idea of having only one control with all the renderers for all cells. If one implements a control for a special case of optionset and another one for Boolean, you might have to bundle them in one control. It depends on which view is applied. Maybe is a good idea to create a renderer controls which knows

But this control is not only a use-case for special editors. It could be a great way to implement some kind of calculated columns, which doesn’t have to be saved in the Dataverse. That case doesn’t need to be generic.

Looking forward to hear about your use-cases.


35 thoughts on “Power Apps Grid Control – First Glimpse to the Cell Renderer and Editors

Add yours

  1. Great step! Thanks Diana always bring good news! Also found more interesting things on Wave2.
    I’m quite happy to see the control can be customized in ‘PCF’ way.

  2. Hi Diana, thank you for your article and a good tip how to make grids easier than the whole PCF grid, rendering works great but I have a question. There is a button Edit Filters above the grid. When I edit the filters, the filters don’t actually work. Like nothing happens. Is it my fault or it doesn’t work properly yet? Because I am used to use that button and edit filters on my custom pcf for datasets. Thanks Dan

      1. Thank you for trying it out πŸ™‚ I’ll try to figure it out where I have a mistake when I have some spare time πŸ™‚

    1. Hi Dan,
      I’ve just relized that my “Edit Filters” button stopped working to me too. Actually the “Edit filters” doesn’t show the added filter nether.
      The error is not on your side, you just got the bug sooner than me.

      1. Hi Diana,
        thank you for the feed back, that is strange that it worked for you for a while and you get the bug latter. Now I know it’s not my fault πŸ™‚

  3. Hi Diana,
    I followed this article and most revevant docs in Microsoft learn, but my customizer control deosn’t work at all. When switch to (Preview) Power Grid view in my app, I could not see any change. The control’s full name is correct, control, entity and app are in the same solution.
    I just added some renderer:

    export const generateCellRendererOverrides = (colors : any) => {
    const cellRendererOverrides: CellRendererOverrides = {
    [“Text”]: (props, col) => {
    // Render all text cells in green font
    return ({props.formattedValue})
    [“FloatingPoint”]: (props, col) => {
    // Render all text cells in green font
    return ({props.formattedValue})
    [“Integer”]: (props, col) => {
    // Render all text cells in green font
    return ({props.formattedValue})
    [“Decimal”]: (props, col) => {
    // Render all text cells in green font
    return ({props.formattedValue})
    But seems nothing responds to this customizer control. What problem could it be?

    Thank you,

    1. About the name: the description in the old customizing is wrong: it shouldn’t be “PublisherPrefix_Namespace_ControlName”. It is
      Maybe that’s why is not loaded at all.
      I guess you need to debug, and see if the the “init” method get’s called. If yes, you have a starting point. If not, you need to make some tries with the name. And you could also check if the PCF and the customizing is published.

    1. Hi GK,
      Yes, I saw that too. Last night I was working on a new PCF for Power Apps Grid, and suddenly it stopped working for all controls in my environment. I don’t think it’s about the Wave 1/2023. Probably one of those updates happening on weekends. I’ve reported this.. let’s see when we get a fix.

      1. Thank you!
        If you have any news about this, I would really be grateful if you could report back to us.

  4. Hi Diana, we’re in the same boat with our PA Grid controls suddenly not working. Have you heard anything back from Microsoft? It’s a little worrying that it’s been over a week.

  5. Hello Diana, I’ve recently tried my hand around this PA Editable Grid but while trying to replicate one of your examples I came accross some unexpected behaviour on my parts. I’ve implemented the two-options with the smiley faces like you did with similar code -only changing the columns names for it to work in my view- the smileys appear but whenever I click on them it doesnt change the value : the smiley is red at first and it’s located in the middle of the field, then when I click on it, the smiley turn green and goes on the left side of the field and it doesn’t save the change of the value. Do you have any idea of why it might not be working correctly ? Since it’s still in “preview” mode I’m afraid it might still be a little buggy but if you have any suggestions I’m eager to hear them πŸ˜€ Have a good one!

    1. Hi Arnaud,
      It’s a little hard to say without the code. I’ve just checked and my example still works.
      Maybe you have a small difference. The boolean is a little tricky, because with only one click we want to change the row in edit mode and set the change.

      If the line is not in edit mode, the code inside the cellRenderOverrides props.startEditing() is taking care to change the row in edit mode. Then this line of code inside of the editor is actually changing the value. (https://github.com/brasov2de/GridCustomizerControl/blob/main/CellRenderer/DianaGridCustomizerControl/Customizer/CellEditorOverrides.tsx#:~:text=rendererParams.onCellValueChanged(value%3D%3D%3Dtrue%20%3F%20%221%22%20%3A%20%220%22)%3B%20//autochange%20value%20on%20click)
      The further clicks will call the onChange function. When teh user leaves the row, the value should be saved.

      Maybe you can debug that functions.

      1. Hi again Diana,

        It seems like it was indeed a boolean issue, somehow it kept telling me that defaultProps.value as string === “1” was always false whatever the value of defaultProps.value was, I changed to defaultProps.value === true (and changed every 1 and 0 to true and false in the rest of the code aswell) and it started to work, it changes the value as expected and I can now exit the editing mode right after it changes the value so it seems like it’s fixed now πŸ˜€

        Thanks again for your answer, I wanted to add that since I started creating PCF components all of the articles of your blog have been a huge help for me to learn how these components work and saved me tons of times and countless searches, thanks a bunch Diana πŸ™‚ !

  6. Hello Diana,

    How to Private method in CustomRendererOverrides file? i want to manupulate each cell based on cell field name and i want to call private function from cell rendereroverrides to avoid huge code in single block.

    1. Hi Krishna,
      You could make different files, and export the functions who need to be called. Not sure if I understand the need to call a private method.
      Or you can return self made react components, so each component is taking care of it’s job. Like I did with my ColorfulDropDown component: https://github.com/brasov2de/GridCustomizerControl/blob/main/CellRenderer/DianaGridCustomizerControl/Customizer/CellEditorOverrides.tsx#LL28C1-L28C1
      Or maybe you mean using a closure, so a function which generates the cellRenderOverrides… Then you can have internal function inside the closure. Similar to this one: https://github.com/brasov2de/GridCustomizerControl/blob/main/CellRenderer/DianaGridCustomizerControl/Customizer/CellRendererOverrides.tsx ?

  7. Hello Diana, Thanks for the response. Lets say of the field datatype is text and there are many fields to render differently based on field name and i want to create separate render function based on field name and call that function in text datatype or optionset datatype based on field name as we write separate block of code in c# and reuse same function in different places. Pls suggest how to write separate function with some sample. when i tried to add separate function above export or below its throwing error.

  8. You can write functions everywhere inside your CellRenderer.tsx file and call them inside the switch based on the field name.
    If you want to define the functions in another file, you need to declare them as
    “export function myFunction(){}” and import the myFunction inside your cellRenderer file.

    As I said, the other approach is to define React components, which you include inside your return for your render function. It could be even more react components, and you decide in the switch, what component should be called.

  9. Thanks Diana, i have prepared one collection in index.ts file now how to pass that collection to cellrenderer file? can you give one sample code to import that in cellrenderer?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Website Powered by WordPress.com.

Up ↑

%d bloggers like this: