Kendo React Grid: onRowDoubleClick stops working with custom rows & Selection Aggregates

1 Answer 12 Views
Grid
Artem
Top achievements
Rank 1
Artem asked on 10 Nov 2025, 02:41 PM

I have implemented Selection Aggregates to count content inside cells. For this I use the onSelectionChange prop, passing a selectionChange function that calls getStatusData from '@progress/kendo-react-grid' and stores the result in the statusData state.

Recently I added a requirement to highlight the row when I select a cell in that row, so I decided to use a custom row renderer via the rows prop and pass a row component.

But here’s the problem: as soon as I started using the custom row renderer, the double-click handling that used to work via the Grid's onRowDoubleClick stopped working. I tried handling the double-click directly on the <tr> by attaching an onDoubleClick handler, but that didn't help either.

As far as I can tell, the issue is that when I click a cell, onSelectionChange fires and I update the state with the result of getStatusData (which is necessary for Selection Aggregates). That state update causes my rows to re-render, and the double-click never fires. If I don't use a custom row renderer (which I need for row highlighting), I can attach onSelectionChange on the Grid, update the state on click for Selection Aggregates, and onRowDoubleClick works.

How can I combine Selection Aggregates, row highlighting when selecting a cell (currently implemented with the custom row renderer), and double-click handling?


Link for sandbox: https://codesandbox.io/p/sandbox/keen-andras-kyzf5c

Code:

import * as React from "react";
import {
  Grid,
  GridColumn as Column,
  GridSelectionChangeEvent,
  StatusBar,
  getStatusData,
  StatusItem,
  GridCustomRowProps,
} from "@progress/kendo-react-grid";
import sampleProducts from "./gd-sample-products";

const DATA_ITEM_KEY = "ProductID";

const App = () => {
  const [statusData, setStatusData] = React.useState<StatusItem[]>([
    { type: "count", formattedValue: "0", value: 0 },
  ]);

  const selectionChange = (event: GridSelectionChangeEvent) => {
    console.log("selectionChange single-click");
    setStatusData(
      getStatusData({
        dataItems: sampleProducts,
        target: event.target,
        select: event.select,
        dataItemKey: DATA_ITEM_KEY,
      })
    );
  };

  const CustomRow = (props: GridCustomRowProps) => {
    // console.log("CustomRow props: ", props);
    const available = !props.dataItem.Discontinued;
    const noBgr = { backgroundColor: "" };
    const customBgr = { backgroundColor: "lavender", fontWeight: "bold" };

    return (
      <tr
        {...props.trProps}
        style={available ? noBgr : customBgr}
        onDoubleClick={(e) => console.log("CustomRow onDoubleClick e: ", e)}
        onClick={(e) => {
          console.log("CustomRow single click");
        }}
      >
        {props.children}
      </tr>
    );
  };

  return (
    <>
      <div style={{ padding: "5px", color: "#999" }}>
        <div>Ctrl+Click/Enter - add to selection</div>
        <div>Shift+Click/Enter - select range </div>
      </div>
      <Grid
        rows={{ data: CustomRow }}
        onRowDoubleClick={(e) => console.log("onRowDoubleClick")}
        data={sampleProducts}
        autoProcessData={true}
        dataItemKey={DATA_ITEM_KEY}
        reorderable={true}
        navigatable={true}
        defaultSelect={{
          4: [0],
          5: [0],
          6: [0],
          7: [0],
        }}
        selectable={{ enabled: true, drag: true, cell: true, mode: "multiple" }}
        onSelectionChange={selectionChange}
      >
        <Column title="Products">
          <Column field="ProductID" title="Product ID" width="100px" />
          <Column field="ProductName" title="Product Name" width="300px" />
          <Column field="UnitsInStock" title="Units In Stock" />
          <Column field="UnitsOnOrder" title="Units On Order" />
          <Column field="ReorderLevel" title="Reorder Level" />
          <Column field="Discontinued" title="Discontinued" />
          <Column field="FirstOrderedOn" title="Date" format="{0:d}" />
        </Column>
        <StatusBar data={statusData} />
      </Grid>
    </>
  );
};
export default App;

1 Answer, 1 is accepted

Sort by
1
Accepted
Yanko
Telerik team
answered on 11 Nov 2025, 09:07 AM

Hello, Artem,

Thank you very much for the provided example and the detailed explanation. I tested the sample and reproduced the described behaviour.

It occurs because the row rerenders after the first click due to the change in the selection state. You can fix this by memorizing the Custom Row using the useCallback hook:

  const CustomRow = React.useCallback((props: GridCustomRowProps) => {
    // console.log("CustomRow props: ", props);
    const available = !props.dataItem.Discontinued;
    const noBgr = { backgroundColor: "" };
    const customBgr = { backgroundColor: "lavender", fontWeight: "bold" };

    return (
      <tr
        {...props.trProps}
        style={available ? noBgr : customBgr}
        onDoubleClick={(e) => console.log("CustomRow onDoubleClick e: ", e)}
        onClick={(e) => {
          console.log("CustomRow single click");
        }}
      >
        {props.children}
      </tr>
    );
  }, []);

I updated the provided example to showcase the solution:

Please do not hesitate to ask if further questions arise.

Regards,
Yanko
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
Grid
Asked by
Artem
Top achievements
Rank 1
Answers by
Yanko
Telerik team
Share this question
or