Как заменить «Вы уверены?» на «Отменить» — 5 шагов и рабочая схема

«Вы уверены, что хотите удалить?» — и все жмут «Да». Не читая. Потому что за месяц этот вопрос задавали двести раз, и все двести раз ответ был «да».
А потом человек удаляет не тот файл — и диалог его не спас. Он ловит ошибку «я случайно нажал», но не ловит ошибку «я нажал осознанно, но не на том элементе». Вторая случается чаще.
Есть подход надёжнее: удалить сразу и дать возможность вернуть. Разберём по шагам.
Кстати, стандарт доступности WCAG (критерий 3.3.4) для действий с чужими или важными данными требует одно из трёх на выбор: действие обратимо, данные проверены, либо есть подтверждение. То есть «Отменить» — не полумера, а полноправная альтернатива. Там же прямо оговорено, что подтверждение на каждое сохранение записи стандарт не требует.
Шаг 1. Раздели действия на три корзины
Не всё подряд нужно делать отменяемым — иначе ты закопаешься.
- Обычные (снять галочку, убрать из избранного) — ни диалога, ни отмены. Человек просто нажмёт ещё раз.
- Заметные (удалить задачу, письмо, фото) — сюда ставим отмену. Это основная корзина.
- Необратимые (закрыть аккаунт, оплатить, отправить письмо реальному адресату) — здесь подтверждение остаётся, и не галочкой, а вводом: попроси напечатать имя проекта. Это единственный способ заставить прочитать.
Дальше работаем только со второй корзиной.
Шаг 2. Сделай удаление обратимым в базе
Отмена невозможна, если строка физически удалена. Поэтому вместо DELETE ставим пометку:
ALTER TABLE tasks ADD COLUMN deleted_at timestamptz;
-- «удаление»
UPDATE tasks SET deleted_at = now() WHERE id = $1;
-- отмена
UPDATE tasks SET deleted_at = NULL WHERE id = $1;
И один раз проходим по всем выборкам, добавляя WHERE deleted_at IS NULL. Забытый фильтр в одном запросе — самая частая беда этого подхода: удалённая задача вдруг всплывает в поиске или в счётчике.
Если база у тебя есть — это правильный путь. Хранить «удалённое» в памяти сервера нельзя: перезапустится процесс, и отменять станет нечего.
Настоящее удаление делает фоновая задача — раз в сутки чистит всё, что помечено раньше чем месяц назад.
Шаг 3. Убери элемент из интерфейса мгновенно
Отмена работает, только если удаление ощущается мгновенным. Никаких спиннеров на строке списка: убираем элемент сразу, запрос идёт в фоне. Это ровно оптимистичный интерфейс — со всеми его правилами, включая обязательную ветку ошибки.
function deleteTask(task) {
setTasks(prev => prev.filter(t => t.id !== task.id)); // сразу
showUndo(task); // шаг 4
api.softDelete(task.id).catch(() => {
setTasks(prev => [...prev, task]); // не получилось — вернули
showError('Не удалось удалить');
});
}
Обрати внимание: в catch мы возвращаем элемент на место и говорим об этом. Без этого приложение будет молча «терять» удаления.
Шаг 4. Покажи окно отмены — и не убивай его таймером
Плашка «Задача удалена — Отменить» появляется внизу или сверху. Обычно это тост, но с одной важной поправкой.
Как только внутри появилась кнопка, автоматический таймер становится проблемой: человек читает медленнее, тянется мышью — а плашка уже исчезла, и вернуть нечего. Стандарт доступности требует, чтобы любое ограничение по времени можно было отключить, растянуть или продлить.
Практическое решение — три правила:
- держим плашку заметно дольше обычного тоста (7–10 секунд, не 3);
- ставим таймер на паузу при наведении мыши и при попадании фокуса с клавиатуры;
- даём кнопку «Закрыть», чтобы отпустить плашку раньше срока.
Кнопка «Отменить» должна быть настоящей кнопкой, доступной с клавиатуры, — а не кликабельным текстом.
Шаг 5. Реши, когда уходит настоящий запрос
Здесь развилка, и от неё зависит надёжность.
Вариант «отложить запрос»: ждём 7 секунд, потом отправляем удаление; нажали «Отменить» — просто не отправляем. Плюс: не нужна колонка deleted_at. Минус: человек закрыл вкладку до срабатывания таймера — и удаление не произошло вовсе. В интерфейсе оно исчезло, в базе осталось. При следующем заходе «удалённая» задача возвращается сама.
Вариант «пометка сразу»: помечаем deleted_at немедленно, отмена снимает пометку. Плюс: состояние честное на любом устройстве, вкладку можно закрывать. Минус: нужен запрос на отмену и колонка в таблице.
Второй вариант надёжнее — бери его, если есть база. Первый годится для черновиков и локальных списков.
Что получится
Обычный сценарий: человек нажал «Удалить» — строка исчезла мгновенно, внизу плашка с кнопкой. Через десять секунд плашка ушла, запись помечена удалённой, ещё через месяц исчезла физически.
Сценарий ошибки: человек понял, что удалил не то, нажал «Отменить» — строка вернулась на своё место в списке. Ни одного модального окна за всю сессию.
Это, по сути, тот же откат, что и в деплое, только применённый к одному действию пользователя.
Отмену нужно делать для всего?
Нет. Для необратимого (оплата, закрытие аккаунта) отмена невозможна — там остаётся подтверждение с осмысленным вводом. Для мелочей она избыточна.
Сколько держать возможность отмены?
В интерфейсе — 7–10 секунд, пока видна плашка. В базе — намного дольше: месяц пометки стоит копейки и не раз выручит, когда человек напишет через неделю «верните, пожалуйста, тот проект».
А если удаляют сразу несколько элементов?
Одна плашка на всю операцию: «Удалено 12 задач — Отменить». Двенадцать плашек подряд — верный способ, чтобы не заметили ни одной.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





