When using MUI Data Grid, you might need to navigate input fields with arrow keys. By default, arrow keys also scroll the grid, disrupting the user experience. This post will show how to disable grid scrolling and enable smooth navigation in input fields.
The Problem
Imagine you have a Data Grid with several rows, each containing input fields. Users expect to use the arrow keys to move the cursor within these input fields. Unfortunately, the default behavior of the MUI Data Grid causes the entire grid to scroll when arrow keys are pressed, making it difficult for users to edit the input values efficiently.
The Solution
To solve this problem, we need to override the default keyboard event handling for the arrow keys when an input field is focused. We'll create a reusable utility function in TypeScript to handle this behavior and apply it to the Data Grid's onKeyDown
event.
Here's the utility function:
export const handleArrowKeyNavigation = (event: React.KeyboardEvent<HTMLDivElement>): void => {
if (event.target instanceof HTMLInputElement) {
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
event.stopPropagation();
}
}
};
This function checks if the focused element is an input field and stops the propagation of the arrow key events, allowing users to navigate within the input field without affecting the Data Grid's scrolling.
Implementing the Utility Function
Next, we'll implement this utility function in our Data Grid component:
import React from 'react';
import { DataGrid } from '@mui/x-data-grid';
import { useForm, FormProvider, useFieldArray } from 'react-hook-form';
import { handleArrowKeyNavigation } from './utils/handleArrowKeyNavigation';
const CustomDataGrid: React.FC = () => {
const methods = useForm({
defaultValues: {
rows: [
{ id: 1, firstName: 'John', lastName: 'Doe' },
{ id: 2, firstName: 'Jane', lastName: 'Smith' },
{ id: 3, firstName: 'Mike', lastName: 'Johnson' },
],
},
});
const { control, setValue } = methods;
const { fields } = useFieldArray({
control,
name: 'rows',
});
const handleInputChange = (index: number, field: string, value: string) => {
setValue(`rows.${index}.${field}`, value);
};
const columns = [
{
field: 'firstName',
headerName: 'First Name',
width: 150,
editable: true,
renderHeader: (params) => (
<input
type="text"
placeholder="First Name"
// **** Here how it is used ****
onKeyDown={handleArrowKeyNavigation}
onChange={(event) => handleInputChange(params.api.getRowIndex(params.id), 'firstName', event.target.value)}
/>
),
},
{
field: 'lastName',
headerName: 'Last Name',
width: 150,
editable: true,
renderHeader: (params) => (
<input
type="text"
placeholder="Last Name"
onKeyDown={handleArrowKeyNavigation}
onChange={(event) => handleInputChange(params.api.getRowIndex(params.id), 'lastName', event.target.value)}
/>
),
},
];
return (
<FormProvider {...methods}>
<div style={{ height: 400, width: '100%' }}>
<DataGrid rows={fields} columns={columns} />
</div>
</FormProvider>
);
};
export default CustomDataGrid;
By adding the handleArrowKeyNavigation
function to the onKeyDown
event of the Data Grid, we ensure that arrow key events are handled correctly, providing a seamless user experience.
Testing the Utility Function
To ensure our utility function works as expected, we can write unit tests using Jest and React Testing Library:
import { handleArrowKeyNavigation } from './handleArrowKeyNavigation';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
describe('handleArrowKeyNavigation', () => {
it('should stop event propagation of ArrowLeft key', () => {
const stopPropagation = jest.fn();
const event = {
key: 'ArrowLeft',
target: document.createElement('input'),
stopPropagation,
} as unknown as React.KeyboardEvent<HTMLDivElement>;
handleArrowKeyNavigation(event);
expect(stopPropagation).toHaveBeenCalled();
});
it('should stop event propagation of ArrowRight key', () => {
const stopPropagation = jest.fn();
const event = {
key: 'ArrowRight',
target: document.createElement('input'),
stopPropagation,
} as unknown as React.KeyboardEvent<HTMLDivElement>;
handleArrowKeyNavigation(event);
expect(stopPropagation).toHaveBeenCalled();
});
it('should not stop event propagation of other keys', () => {
const stopPropagation = jest.fn();
const event = {
key: 'Enter',
target: document.createElement('input'),
stopPropagation,
} as unknown as React.KeyboardEvent<HTMLDivElement>;
handleArrowKeyNavigation(event);
expect(stopPropagation).not.toHaveBeenCalled();
});
it('should not stop event propagation of non-input elements', () => {
const stopPropagation = jest.fn();
const event = {
key: 'ArrowLeft',
target: document.createElement('div'),
stopPropagation,
} as unknown as React.KeyboardEvent<HTMLDivElement>;
handleArrowKeyNavigation(event);
expect(stopPropagation).not.toHaveBeenCalled();
});
});
These tests cover various scenarios to ensure the utility function behaves as expected.
Conclusion
We can significantly enhance the user experience by customizing the keyboard event handling for input fields within the MUI Data Grid. This solution allows users to navigate within input fields using arrow keys without disrupting the grid's scrolling behavior.
Feel free to implement this solution in your projects and share your feedback. Happy coding!
Note: I used generative AI to quickly write my problem and solution as a blog post. Thanks for reading. I hope it helps many, as I could not find a solution to this problem online.
Top comments (2)
I'm surely going to try this in one of my project. As a beginner developer I was hopeless to fix it so I left it π
Good Read. Will definitely try this!