Управление фокусом в диалогах

MUI (Material-UI) предоставляет мощные возможности для работы с компонентами диалогов (Dialog) в React-приложениях, включая управление фокусом. Управление фокусом — ключевой аспект создания доступного интерфейса, поскольку обеспечивает корректную навигацию с клавиатуры и взаимодействие с экранными считывателями.


Автоматическая установка фокуса

Компонент Dialog в MUI по умолчанию автоматически устанавливает фокус на первый фокусируемый элемент внутри диалога при его открытии. Это поведение задается свойством disableAutoFocus, которое по умолчанию равно false.

Пример использования:

import React, { useState } from 'react';
import { Dialog, DialogTitle, DialogContent, TextField, Button } from '@mui/material';

function ExampleDialog() {
  const [open, setOpen] = useState(false);

  const handleOpen = () => setOpen(true);
  const handleClose = () => setOpen(false);

  return (
    <>
      <Button variant="outlined" onCl ick={handleOpen}>
        Открыть диалог
      </Button>
      <Dialog open={open} onCl ose={handleClose}>
        <DialogTitle>Введите данные</DialogTitle>
        <DialogContent>
          <TextField label="Имя" autoFocus fullWidth margin="normal" />
          <TextField label="Email" fullWidth margin="normal" />
        </DialogContent>
      </Dialog>
    </>
  );
}

Ключевые моменты:

  • autoFocus на TextField внутри диалога гарантирует установку фокуса на этот элемент при открытии.
  • Если autoFocus не задан, MUI фокусирует первый доступный фокусируемый элемент внутри диалога.

Отключение автоматического фокуса

Для случаев, когда требуется вручную управлять фокусом, можно отключить автозахват фокуса через disableAutoFocus={true}:

<Dialog open={open} onCl ose={handleClose} disableAutoFocus>
  ...
</Dialog>

После этого фокус не будет автоматически перемещён при открытии, что позволяет программно устанавливать его в нужный элемент с использованием ref.


Перемещение фокуса с помощью ref

Для более гибкого управления часто используют React.useRef и метод focus():

import React, { useState, useRef, useEffect } from 'react';
import { Dialog, DialogTitle, DialogContent, TextField, Button } from '@mui/material';

function CustomFocusDialog() {
  const [open, setOpen] = useState(false);
  const nameRef = useRef(null);

  useEffect(() => {
    if (open && nameRef.current) {
      nameRef.current.focus();
    }
  }, [open]);

  return (
    <>
      <Button onCl ick={() => setOpen(true)}>Открыть диалог</Button>
      <Dialog open={open} onCl ose={() => setOpen(false)} disableAutoFocus>
        <DialogTitle>Регистрация</DialogTitle>
        <DialogContent>
          <TextField label="Имя" inputRef={nameRef} fullWidth margin="normal" />
          <TextField label="Пароль" fullWidth margin="normal" />
        </DialogContent>
      </Dialog>
    </>
  );
}

Особенности подхода:

  • Использование inputRef позволяет напрямую ссылаться на DOM-элемент.
  • useEffect отслеживает изменение состояния открытия диалога и устанавливает фокус после монтирования.

Возврат фокуса после закрытия диалога

MUI автоматически возвращает фокус на элемент, вызвавший открытие диалога, если используется стандартное API без отключения автофокуса. Для кастомного управления можно сохранять ссылку на кнопку:

const triggerRef = useRef(null);

<Button ref={triggerRef} onCl ick={() => setOpen(true)}>Открыть</Button>
<Dialog
  open={open}
  onCl ose={() => {
    setOpen(false);
    triggerRef.current.focus();
  }}
>
  ...
</Dialog>

Важные моменты:

  • Сохранение исходного фокуса критично для доступности.
  • Такой подход особенно полезен, когда автозахват фокуса был отключен (disableAutoFocus).

Установка фокуса на первый элемент при навигации с клавиатуры

MUI обеспечивает траппинг фокуса внутри диалога: при открытом диалоге пользователи клавиатуры не могут перейти к элементам вне него. Для этого используется FocusTrap внутри Modal. Параметры управления:

  • disableEnforceFocus: отключает принудительное удержание фокуса.
  • disableRestoreFocus: отключает автоматический возврат фокуса после закрытия.

Пример:

<Dialog
  open={open}
  disableEnforceFocus
  disableRestoreFocus
>
  ...
</Dialog>

Сочетание с компонентами MUI

Для комплексных форм внутри диалога рекомендуется:

  • Использовать autoFocus только на самом важном поле.
  • Для динамических компонентов (например, списков или табов) применять ref и focus() после рендеринга.
  • Проверять корректность перемещения фокуса при всех способах закрытия диалога (кнопка, Esc, клик вне области).

Практические рекомендации

  1. Всегда указывать первичный элемент для фокуса. Это улучшает доступность.
  2. Сохранять элемент, открывший диалог, для возврата фокуса.
  3. Тестировать клавиатурную навигацию. Проверять Tab, Shift+Tab, Esc.
  4. Избегать конфликта autoFocus и ручного ref.focus(). Либо одно, либо другое.

Управление фокусом в диалогах MUI — это комбинация автоматических механизмов, встроенных в Dialog и Modal, и возможностей ручного контроля через ref, autoFocus и состояния компонентов. Правильное использование этих инструментов обеспечивает удобство, доступность и предсказуемое поведение интерфейса.