Add Rows to AG Grid with a Pinned Row

This blog demonstrates how to add rows in AG Grid using a Pinned Row and the Transaction API, avoiding the need for a separate form UI.

You will learn how to:

  1. Implement and style an empty pinned row.
  2. Listen for and process cell edits within the pinned row.
  3. Insert a new row using the data entered by the user.
  4. Flash the new row to draw the user’s attention.
0:00
/0:15

💡
If you're looking to add multiple blank rows, similar to the functionality found in Google Sheets and Excel, read our Adding & Deleting Rows via the Context Menu blog.

Example & Source Code

In the example below, entering data into the pinned top row triggers automatic addition of a new row, highlighted by a green flash as visual confirmation.

Source Code: React | Angular | Vue | JavaScript

TL;DR

A quick summary of this how-to

Configure Grid Options

const [pinnedRowData, setPinnedRowData] = useState<>({});

<AgGridReact<AthleteData>
  ...
  // Pin an empty row at the top for data entry
  pinnedTopRowData={[pinnedRowData]} 
  // Listen for pinned row edits
  onCellEditingStopped={onCellEditingStopped} 
/>

Handle Pinned Row Cell Edits

// Checks if all required fields in the pinned row are filled
const isPinnedRowComplete = () => {
  return columnDefs.every((colDef) => {
    if (!colDef.field) return false;

    const v = pinnedRowData[colDef.field!];
    return v != null && v !== '';
  });
};
  
const onCellEditingStopped = useCallback((params: CellEditingStoppedEvent) => {
  // Only process pinned row edits
  if (params.rowPinned !== 'top') return;
  
  // Check all pinned row cells have a value
  if (isPinnedRowComplete()) {
    addNewRow();
  }
}, [pinnedRowData]);

Add a New Row

const addNewRow = () => {
  // Add the new row to the grid data
  const transaction = gridRef.current?.api.applyTransaction({
    add: [pinnedRowData],
  });

  // Reset the input row for next entry
  setPinnedRowData({});
  gridRef.current?.api.setGridOption('pinnedTopRowData', [pinnedRowData]);

  // Flash the newly added row to draw attention
  // Note: add delay to ensure transaction & updates complete
  setTimeout(() => {
    gridRef.current?.api.flashCells({
      rowNodes: transaction?.add,
    });
  }, 100);
};

Configuring the Data Grid

There are a few Grid Options required for this demo, including:

  • pinnedRowTopData - Initialises pinned row for user data entry. The data will be automatically updated by the grid whenever a user edits the value of a cell.
  • rowNumbers - Enables the row number column. The valueFormatter disables this for pinned rows.
  • onCellEditingStopped - Defines a callback function that is called whenever a user has stopped editing a cell.
// Show row numbers for non-pinned rows
const rowNumbersOptions = {
  valueFormatter: (params: ValueFormatterParams) => {
    return params?.node?.rowPinned ? '' : params?.value;
  },
};

<AgGridReact
  ...Other options, including rowData, colDefs, etc...
  // Pin an empty row at the top for data entry
  pinnedTopRowData={[pinnedRowData]} 
  // Show row numbers for non-pinned rows
  rowNumbers={rowNumbersOptions} 
  // Listen for pinned row edits
  onCellEditingStopped={onCellEditingStopped} 
/>

Styling the Pinned Row

All pinned rows have the ag-row-pinned CSS class applied to them, so to style the pinned top row, override the CSS class in the application styles:

/* Pinned input row */
.ag-row-pinned {
  background-color: #f8f9fa;
  font-style: italic;
  color: #6c757d;
  border-bottom: 2px solid #e9ecef;
}

.ag-row-pinned:hover {
  cursor: text;
}

Styling Pinned Row Cell Edits

cellClassRules allow you to apply custom CSS classes based on the value of a cell. To apply a class whenever the user enters a value into a pinned row cell, provide a cellClassRules object that returns the pinned-cell-editing class when the node is rowPinned and has a value.

const cellClassRules = {
  'pinned-cell-editing': (params: CellClassParams) => params?.node?.rowPinned && params.value,
};

const defaultColDef: ColDef = {
  ...
  cellClassRules,
};

The pinned-cell-editing class in this demo adds an orange border to the left of the cell and slightly changes the text and background:

/* Cells with values in pinned row */
.pinned-cell-editing {
  font-style: normal;
  color: #333;
  font-weight: 500;
  background-color: #fff3cd;
  border-left: 2px solid #fd7e14;
}

/* Hover effect for empty cells */
.pinned-row .ag-cell:not(.pinned-cell-editing):hover {
  background-color: #f1f3f4;
}

Handling Pinned Row Cell Edits

In the onCellEditingStopped callback, we need to check that every pinned row cell has a value. We do this in the isPinnedRowComplete() function by looping through each field in our column definition and then looking up the pinnedRowData for that column. If all columns have a value, we can add the new row; otherwise, we can ignore the edit event:

const isPinnedRowComplete = () => {
  return columnDefs.every((colDef) => {
    if (!colDef.field) return false;

    const v = pinnedRowData[colDef.field!];
    return v != null && v !== '';
  });
};

const onCellEditingStopped = useCallback((params: CellEditingStoppedEvent) => {
  // Only process pinned row edits
  if (params.rowPinned !== 'top') return;

  // Check all pinned row cells have a value
  if (isPinnedRowComplete()) {
    addNewRow();
  }
}, [pinnedRowData]);

Updating the Data Grid

There are a few steps to take when adding a new row:

Adding a new row

Firstly, we can use the applyTransaction API to add the pinnedRowData to the grid by supplying this via the add property. There is an optional addIndex property to specify where to add the row, which defaults to the end of the data.

Clearing the pinned row

Next, we need to clear the data from the pinned row:

Flashing new row

Finally, we can use the flashCells API to flash the newly added row. We provide the result from the transaction to ensure the flash only occurs after a row has been added successfully. This is wrapped in a setTimeout to ensure the transaction is complete, along with any model updates (e.g. sorting, filtering, etc...).

const addNewRow = useCallback(() => {
  // Add the new row to the grid data
  const transaction = gridRef.current?.api.applyTransaction({
    add: [pinnedRowData],
  });
  
  // Reset the input row for next entry
  setPinnedRowData({});
  gridRef.current?.api.setGridOption('pinnedTopRowData', [pinnedRowData]);
  
  // Flash the newly added row to draw attention
  // Note: add delay to ensure transaction & updates complete
  setTimeout(() => {
    gridRef.current?.api.flashCells({
      rowNodes: transaction?.add,
    });
  }, 100);
}, [pinnedRowData]);

Conclusion

This blog shows developers how to add rows in AG Grid by using a pinned top row and the Transaction API. It covers configuring an editable pinned row, capturing and validating user input, programmatically adding new rows, and visually highlighting inserted data. Code examples for React, Angular, Vue, and plain JavaScript are included to illustrate the approach clearly.

Learn more about the features used in this blog on our docs:

Next Steps

New to AG Grid? Get started in minutes, for free:

Considering AG Grid Enterprise? Request a free two-week trial licence to test your application in production and get direct access to our support team.

Happy coding!