Data Grid - Copy and paste
Copy and paste data using clipboard.
Clipboard copy
You can copy selected grid data to the clipboard using the Ctrl+C (⌘ Command+C on macOS) keyboard shortcut.
The copied cell values are separated by a tab (\t) character and the rows are separated by a new line (\n) character.
The priority of the data copied to the clipboard is the following, from highest to lowest:
- If more than one cell is selected (see Cell selection), the selected cells are copied
- If one or more rows are selected (see Row selection), the selected rows are copied
- If there is a single cell selected, the single cell is copied
Add new rows from copied data
The onClipboardCopy prop can be used to capture the copied data and reuse it outside of the regular paste flow—for example, to duplicate the selected rows as new rows when a button is clicked, instead of overwriting the existing ones.
The demo below stores the data copied with Ctrl+C (⌘ Command+C on macOS) and adds it back as new rows when the button is clicked, while leaving the regular copy and paste behavior untouched.
Triggering a copy without the keyboard shortcut
To let users copy the current selection from a button (or any other UI, such as a context menu), combine public APIs: apiRef.current.getSelectedCellsAsArray() and getCellSelectionModel() for cell selection, apiRef.current.getDataAsCsv() for row selection, and gridFocusCellSelector as a fallback for a single focused cell.
Clipboard content:
Nothing copied yetClipboard paste
The paste operation only affects cells in the columns that are editable.
Same as with editing, you can use valueParser to modify the pasted value and valueSetter to update the row with new values.
See Value parser and value setter section of the editing documentation for more details.
The behavior of the clipboard paste operation depends on the selection state of the Data Grid and the data pasted from clipboard. The priority is the following, from highest to lowest:
- If multiple cells are selected (see Cell selection), the selected cells are updated with the pasted values.
- If one or more rows are selected (see Row selection), the selected rows are updated with the pasted values.
- If a single cell is selected, the values are pasted starting from the selected cell.
Keyboard shortcuts
The paste operation can be triggered by the following keyboard shortcuts:
- Ctrl+V (⌘ Command+V on macOS) pastes clipboard content into the selected cells.
- Ctrl+D (⌘ Command+D on macOS) fills down—copies the value of the selected cell into the cell below. If multiple cells are selected in a column, the top cell's value is copied into the cells below it.
- Ctrl+R (⌘ Command+R on macOS) copies the value from the leftmost cell of each selected row into the cells to its right. When a single cell is selected, the value is copied to the cell directly to the right, and the selection moves right. When a single column with multiple rows is selected, the values are copied to the column to the right.
Drag to fill
To let the users copy the values using dragging, similar to the spreadsheet applications like "Excel", pass the cellSelectionFillHandle prop to the Data Grid.
When passed, a small handle appears at the bottom-right corner of the selected editable cell.
Drag it up or down to fill rows, or left and right to fill adjacent columns.
Disable clipboard paste
To disable clipboard paste, set the disableClipboardPaste prop to true:
Disable pasting to the specific cells within a row
The clipboard paste operation respects the cell editing rules. Use this to prevent pasting into certain cells based on row data or other conditions.
The demo below shows a product inventory grid with the following paste restrictions:
- Price column: Cannot be pasted in archived products
- Status column: Cannot be pasted in any row
- Last Modified column: Cannot be pasted in any row
Try selecting multiple cells and pasting data.
Cells marked as non-editable by isCellEditable will not be updated.
Persisting pasted data
Clipboard paste uses the same API for persistence as Editing—use the processRowUpdate prop to persist the updated row in your data source:
processRowUpdate?: (newRow: R, oldRow: R) => Promise<R> | R;
The row will be updated with a value returned by the processRowUpdate callback.
If the callback throws or returns a rejected promise, the row will not be updated.
The demo below shows how to persist the pasted data in the browser's sessionStorage.
Add rows on paste
By default, the pasted rows that go past the last row are ignored.
To add rows for them, pass a createRows() function to the clipboardPasteOptions prop.
It receives the number of rows to create and their pasted data, and returns the new rows, or a promise that resolves with them.
Each row needs a unique id, and can set default values for other fields.
<DataGridPremium
clipboardPasteOptions={{
createRows: ({ count }) =>
Array.from({ length: count }, () => ({ id: randomId() })),
}}
disableRowSelectionOnClick
/>
Rows are added only when the paste starts from a single cell.
By default, a click on a cell also selects its row, so set disableRowSelectionOnClick to keep the paste from going to the selected row.
The new rows get the pasted values with the same rules as the existing rows, then go through processRowUpdate(), with the row from createRows() as oldRow.
processRowUpdate() can return the row with another id, for example one from your server. If it throws, the row is not added.
The paste, new rows included, is a single undo step.
The clipboardPasteEnd event lists the new rows in its createdRows parameter.
To try it, copy a range of cells, select a cell in the last row, and paste.
Controlled rows
When you control the rows prop, add the new rows to your state in onClipboardPasteEnd().
Otherwise, the next update of rows removes them, along with the undo step of the paste.
const [rows, setRows] = React.useState(initialRows);
<DataGridPremium
rows={rows}
clipboardPasteOptions={clipboardPasteOptions}
processRowUpdate={(newRow) => {
setRows((prevRows) =>
prevRows.map((row) => (row.id === newRow.id ? newRow : row)),
);
return newRow;
}}
onClipboardPasteEnd={({ createdRows }) => {
setRows((prevRows) => [...prevRows, ...createdRows.values()]);
}}
/>;
Don't add the new rows in processRowUpdate(): the Data Grid adds them after it runs, and skips a row whose id is already in the Data Grid.
Undo and redo only change the rows of the Data Grid, so update your state in onUndo() and onRedo() too.
Limitations
- With pagination, rows are added only from the last page. On other pages, the paste stops at the last row of the page.
- New rows are added after the last row, then sorting and filtering apply, so they can move or be hidden.
- A paste that starts while another paste is still adding rows doesn't add rows.
- Adding rows isn't supported with a data source, server-side pagination, tree data, row grouping, or pivoting.
Events
The following events are fired during the clipboard paste operation:
clipboardPasteStart- fired when the clipboard paste operation startsclipboardPasteEnd- fired when all row updates from clipboard paste have been processed
For convenience, you can also listen to these events using their respective props:
onClipboardPasteStartonClipboardPasteEnd
Additionally, there is the onBeforeClipboardPasteStart prop, which is called before the clipboard paste operation starts
and can be used to cancel or confirm the paste operation:
const onBeforeClipboardPasteStart = async () => {
const confirmed = window.confirm('Are you sure you want to paste?');
if (!confirmed) {
throw new Error('Paste operation cancelled');
}
};
<DataGridPremium onBeforeClipboardPasteStart={onBeforeClipboardPasteStart} />;
The demo below uses the Dialog component for paste confirmation.
If confirmed, the Data Grid displays a loading indicator during the paste operation.
Format of the clipboard data
By default, the clipboard copy and paste operations use the following format:
- The cell values are separated by a tab (
\t) character. - The rows are separated by a new line (
\n) character.
You can use clipboardCopyCellDelimiter and splitClipboardPastedText props to change the format:
<DataGridPremium
{...otherProps}
// support comma separated values
clipboardCopyCellDelimiter={','}
splitClipboardPastedText={(text) => text.split('\n').map((row) => row.split(','))}
/>
The demo below uses , (comma) character as a cell delimiter for both copy and paste operations: