Inline cell editing: все нюансы редактирования ячейки в таблице

Полный список микрорешений, которые рождаются при сборке таблицы с редактируемыми ячейками. Иллюстрация к тезису: между макетом и продуктом — серая зона из сотен таких решений.
Абдугафур
Креативный директор, 5x10
Абдугафур
Креативный директор, 5x10

Список микрорешений, которые рождаются при сборке таблицы с редактируемыми ячейками. Иллюстрация к тезису: между макетом и продуктом — серая зона из сотен таких решений.

Вход в режим редактирования

  • клик — курсор встает точно в позицию клика
  • двойной клик — выделяется слово
  • тройной клик — выделяется абзац/вся строка
  • нажатие enter/f2 на выделенной ячейке — курсор в конец текста
  • начало набора символов на выделенной ячейке — содержимое заменяется
  • backspace на выделенной ячейке — очищает содержимое

Выход из режима редактирования

  • enter — сохранить, перейти на ячейку ниже
  • escape — отменить изменения, вернуться в режим навигации
  • tab — сохранить, перейти на следующую ячейку
  • shift+tab — сохранить, перейти на предыдущую ячейку
  • клик за пределами ячейки (blur) — сохранить
  • сохранение через debounce (1 сек после последнего изменения)

Навигация внутри текста (режим редактирования)

  • стрелки — перемещение курсора по тексту (не по таблице!)
  • cmd+left/right — начало/конец строки
  • option+left/right — перемещение по словам
  • shift+стрелки — выделение текста
  • shift+cmd+left/right — выделение до начала/конца строки
  • home/end — начало/конец текста

Навигация по таблице (режим навигации, ячейка выделена но не редактируется)

  • стрелки — перемещение между ячейками
  • tab/shift+tab — следующая/предыдущая ячейка
  • enter — войти в режим редактирования
  • escape — снять выделение
  • home/end — первая/последняя ячейка в строке
  • ctrl+home/end — первая/последняя ячейка в таблице

Перенос строки внутри ячейки

  • shift+enter или option+enter — новая строка внутри ячейки
  • прямая установка value ломает cmd+z (undo внутри ячейки)

Выделение текста

  • двойной клик — выделение слова
  • тройной клик — выделение абзаца
  • react controlled textarea уничтожает выделение при re-render (setState в onFocus вызывает re-render, react переприсваивает value в dom, браузер сбрасывает текущее выделение)
  • решение: не вызывать setState в onFocus, использовать uncontrolled textarea
  • contenteditable в firefox имеет баги с двойным/тройным кликом — textarea таких багов не имеет

Фокус и визуал

  • фокус-ринг (оранжевый в нашем случае) — визуальная обратная связь что ячейка активна
  • фокус-ринг должен появляться мгновенно при клике
  • textarea стилизуется как обычный текст (невидимые границы), выглядит как часть таблицы
  • авторесайз textarea под содержимое (css field-sizing: content или js)

Propagation событий

  • stopPropagation на mousedown/pointerdown/keydown в режиме редактирования — универсальный паттерн всех production-таблиц
  • без этого: клик в ячейку триггерит выделение строки, drag, навигацию по таблице
  • ag grid, handsontable, glide data grid — все используют stopPropagation
  • при выходе из режима редактирования ячейка переэмитирует клавишу (tab, enter) чтобы таблица могла навигировать

Два лагеря ux-паттернов

  • spreadsheet-like (google sheets, airtable, ag grid): клик выделяет ячейку, двойной клик/enter — редактирование. два явных режима. лучше для data-heavy таблиц
  • document-like (notion, linear): клик сразу редактирует. нет режима выделения. лучше для content-focused ui с малым числом редактируемых полей на строку

Как это делают production-приложения

  • Google sheets: canvas + textarea overlay, два режима
  • Notion: contenteditable div, всегда в режиме редактирования
  • Aitable: input/textarea, два режима (selected vs editing)
  • AG-grid: input/textarea, suppressKeyboardEvent callback
  • Handsontable: один textarea на всю таблицу, переиспользуется между ячейками
  • Glide data grid: canvas + overlay textarea, нет dom-элементов на ячейку
  • ни одна production data table не использует contenteditable — только input/textarea

Отправить заявку

Заполняя форму, я принимаю условия политики обработки персональных данных и соглашаюсь на их обработку

Спасибо. Скоро свяжемся
Что-то пошло не так. Попробуйте написать на почту или в телеграм