НачалоОсновыКомпонентыТексты

Диалог

Диалог — модальное окно поверх страницы: его завершают или закрывают, прежде чем вернуться к странице. tk-dialog вмещает короткую задачу, tk-confirm-dialog подтверждает одно действие.

Стабильный Figma
ОбзорИспользованиеAPIДоступность
Rename project Cancel Rename Delete project
<tk-button onclick="document.getElementById('dialog').show()">Rename project</tk-button>
<tk-dialog id="dialog" heading="Rename project">
  <tk-field label="Project name"><tk-input value="Aurora"></tk-input></tk-field>
  <tk-button slot="footer" onclick="this.closest('tk-dialog').close()">Cancel</tk-button>
  <tk-button slot="footer" variant="primary" onclick="this.closest('tk-dialog').close()">Rename</tk-button>
</tk-dialog>
<tk-button tone="danger" onclick="document.getElementById('confirm').show()">Delete project</tk-button>
<tk-confirm-dialog id="confirm" heading="Delete project?" message="This permanently deletes 'Aurora' and all its data." confirm-label="Delete project" danger></tk-confirm-dialog>

Анатомия

Часть tk-dialog tk-confirm-dialog
заголовок heading: заголовок и доступное имя, обязателен heading: конкретный вопрос, обязателен
кнопка закрытия встроена, справа вверху нет; выход — «Отмена»
тело слот по умолчанию; прокручивается message: одна строка о последствиях
подвал слот footer: ваши кнопки, по правому краю «Отмена» и кнопка подтверждения, встроены
подложка затемняет страницу и блокирует её так же
part dialog панель панель

Варианты

<tk-button tone="danger" onclick="document.getElementById('delete').show()">Delete project</tk-button>
<tk-confirm-dialog id="delete" heading="Delete project?" message="This permanently deletes Aurora and all its data." confirm-label="Delete" danger></tk-confirm-dialog>
  • tk-dialog: задача с содержимым. Тело и подвал заполняете вы.
  • tk-confirm-dialog: подтверждает одно действие. Настраивается только атрибутами: нет слотов, кнопки закрытия и прокрутки, ширина всегда 320px. confirm-label обязателен: без него будет только «Отмена».
  • danger: для действия, которое удаляет или которое нельзя отменить. Кнопка подтверждения становится опасной кнопкой, красноватой с красным текстом, а фокус встаёт на «Отмену». Без danger кнопка подтверждения — primary, и фокус на ней.

Если потеря велика, добавьте трение в tk-dialog: держите опасную кнопку отключённой, пока пользователь не отметит Checkbox или не введёт название в Input. Делайте так редко: трение повсюду приучает спешить.

Размеры

size Ширина Для чего
small 320px короткие решения с небольшим содержимым
medium (по умолчанию) 480px большинство форм и задач
large 640px широкое содержимое, например форма в две колонки или таблица
  • Диалог не выходит за окно и оставляет space-16 (16px) с каждой стороны, вплоть до окна 320 × 256px.
  • Длинное содержимое прокручивается в теле, а заголовок и подвал стоят на месте. У края, за которым есть ещё содержимое, оно плавно гаснет. Вбок ничего не прокручивается: возьмите размер шире.
  • У tk-confirm-dialog нет size: ширина 320px и прокрутки нет, поэтому пишите коротко.

Открытие и закрытие

<tk-button onclick="document.getElementById('rename').show()">Rename project</tk-button>
<tk-dialog id="rename" heading="Rename project">
  <form id="rename-form">
    <tk-field label="Project name"><tk-input name="name" value="Aurora" autofocus></tk-input></tk-field>
  </form>
  <tk-button slot="footer" onclick="this.closest('tk-dialog').close()">Cancel</tk-button>
  <tk-button slot="footer" variant="primary" type="submit" form="rename-form">Rename</tk-button>
</tk-dialog>
const dialog = document.getElementById('rename');
dialog.querySelector('form').addEventListener('submit', (event) => {
  event.preventDefault();
  // save the name, then:
  dialog.close('renamed');
});
  • show() открывает диалог, всегда модально. close(value) закрывает его, а в обработчике close значение лежит в returnValue. Фокус возвращается к элементу, который открыл диалог.
  • Подвал находится вне вашей формы, поэтому дайте кнопке отправки form с id формы. <form method="dialog"> диалог не закрывает: вызовите close() при отправке.
  • Поставьте autofocus на первое поле.
Как закрыть tk-dialog tk-confirm-dialog
Esc закрывает закрывает, как «Отмена»
кнопка закрытия закрывает —
клик по подложке закрывает, если в диалоге нет <form> ничего не делает
«Отмена» закрывает; подключаете вы закрывает
главное действие подключаете вы закрывает с returnValue "confirm"
  • Закрытие ничего не сохраняет. Любой выход, кроме главного действия, оставляет returnValue равным "" в tk-dialog и "cancel" в tk-confirm-dialog.
  • persistent отключает Esc и подложку. Кнопка закрытия и кнопки диалога работают по-прежнему. Оставьте это для редких случаев, например принятия юридических условий.
  • Не больше одного подтверждения поверх одного диалога. Esc закрывает верхний.

Несохранённые изменения

Esc и клик по подложке сначала отправляют событие cancel, и preventDefault() оставляет диалог открытым. Так можно спросить, прежде чем введённое пропадёт. Кнопка закрытия и «Отмена» cancel не отправляют.

<tk-confirm-dialog id="discard" heading="Discard changes?" message="Your edits will be lost." cancel-label="Continue editing" confirm-label="Discard changes" danger></tk-confirm-dialog>
<script>
  const dialog = document.getElementById('rename');
  const discard = document.getElementById('discard');
  dialog.addEventListener('cancel', (event) => {
    if (!hasUnsavedChanges()) return;
    event.preventDefault();
    discard.show();
  });
  discard.addEventListener('close', () => {
    if (discard.returnValue === 'confirm') dialog.close();
  });
</script>

Ожидание ответа сервера

preventDefault() на клике по кнопке подтверждения держит tk-confirm-dialog открытым, пока идёт ваш запрос.

const deleteDialog = document.getElementById('delete');
deleteDialog.addEventListener('click', async (event) => {
  const button = event.composedPath().find((node) => node.dataset?.action === 'confirm');
  if (!button) return;
  event.preventDefault();
  button.loading = true;
  await deleteProject();
  button.loading = false;
  deleteDialog.close('confirm');
});