Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Add paragraph about managing focus of custom edit components #9658

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions docs/data/data-grid/editing/CustomEditComponent.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Rating from '@mui/material/Rating';
import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils';
import { DataGrid, useGridApiContext } from '@mui/x-data-grid';

function renderRating(params) {
return <Rating readOnly value={params.value} />;
}

function RatingEditInputCell(props) {
const { id, value, field } = props;
const { id, value, field, hasFocus } = props;
const apiRef = useGridApiContext();
const ref = React.useRef();

const handleChange = (event, newValue) => {
apiRef.current.setEditCellValue({ id, field, value: newValue });
};

const handleRef = (element) => {
if (element) {
const input = element.querySelector(`input[value="${value}"]`);
useEnhancedEffect(() => {
if (hasFocus && ref.current) {
const input = ref.current.querySelector(`input[value="${value}"]`);
input?.focus();
}
};
}, [hasFocus, value]);

return (
<Box sx={{ display: 'flex', alignItems: 'center', pr: 2 }}>
<Rating
ref={handleRef}
ref={ref}
name="rating"
precision={1}
value={value}
Expand Down
14 changes: 8 additions & 6 deletions docs/data/data-grid/editing/CustomEditComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Rating from '@mui/material/Rating';
import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils';
import {
DataGrid,
GridRenderCellParams,
Expand All @@ -13,26 +14,27 @@ function renderRating(params: GridRenderCellParams<any, number>) {
}

function RatingEditInputCell(props: GridRenderCellParams<any, number>) {
const { id, value, field } = props;
const { id, value, field, hasFocus } = props;
const apiRef = useGridApiContext();
const ref = React.useRef<HTMLElement>();

const handleChange = (event: React.SyntheticEvent, newValue: number | null) => {
apiRef.current.setEditCellValue({ id, field, value: newValue });
};

const handleRef = (element: HTMLSpanElement) => {
if (element) {
const input = element.querySelector<HTMLInputElement>(
useEnhancedEffect(() => {
if (hasFocus && ref.current) {
const input = ref.current.querySelector<HTMLInputElement>(
`input[value="${value}"]`,
);
input?.focus();
}
};
}, [hasFocus, value]);

return (
<Box sx={{ display: 'flex', alignItems: 'center', pr: 2 }}>
<Rating
ref={handleRef}
ref={ref}
name="rating"
precision={1}
value={value}
Expand Down
16 changes: 14 additions & 2 deletions docs/data/data-grid/editing/editing.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,17 +362,29 @@ Once a new value is entered into the input, it must be sent to the data grid.
To do this, pass the row ID, the column field, and the new cell value to a call to `apiRef.current.setEditCellValue`.
The new value will be parsed and validated, and the `value` prop will reflect the changes in the next render.

It's important to also handle the [accessibility](/x/react-data-grid/accessibility/) of custom edit components.
When a cell enters edit mode, an element must be focused to provide access via keyboard and for screen readers.
Since multiple cells may be in edit mode at the same time, the `hasFocus` prop will be `true` on the cell that should have focus.
Use this prop to focus the appropriate element.

```tsx
function CustomEditComponent(props: GridRenderEditCellParams) {
const { id, value, field } = props;
const { id, value, field, hasFocus } = props;
const apiRef = useGridApiContext();
const ref = React.useRef();

React.useLayoutEffect(() => {
if (hasFocus) {
ref.current.focus();
}
}, [hasFocus]);

const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value; // The new value entered by the user
apiRef.current.setEditCellValue({ id, field, value: newValue });
};

return <input type="text" value={value} onChange={handleValueChange} />;
return <input ref={ref} type="text" value={value} onChange={handleValueChange} />;
}
```

Expand Down