2025, Oct 20 14:16
DateTimePicker в dbc Modal: как починить dropdown времени
DateTimePicker в dbc Modal мигает и не открывает dropdown времени? Это баг фокуса. Простое решение: enforceFocus=False и withinPortal=False. С примером кода.
Встроить dmc DateTimePicker в dbc Modal кажется простым — пока не включишь выпадающий список времени. Сам пикер отображается, но селектор либо не открывается вовсе, либо мелькнёт и тут же закрывается. Переписывать крупное приложение Dash, отказываясь от Bootstrap‑компонентов ради поддержки DateTimePicker, почти никогда не вариант, поэтому нужен минимальный и надёжный обходной путь.
Воспроизведение проблемы
Сбой появляется, если поместить DateTimePicker внутрь dbc Modal и включить режим выпадающего списка времени. Пока dropdown отключён — компонент работает. Как только его активируешь, ожидаемая панель времени не открывается или на мгновение мигает и исчезает.
from dash import Dash
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
web_app = Dash(name=__name__)
web_app.layout = dmc.MantineProvider([
    dbc.Modal(
        dmc.DateTimePicker(
            timePickerProps={
#               'withDropdown': True,
                'popoverProps': {'withinPortal': False},
            },
        ),
        is_open=True,
    ),
])
 
if __name__ == '__main__':
    web_app.run(debug=True, port=8080)
Включить выпадающий список времени так же просто, как раскомментировать withDropdown. Этого достаточно, чтобы проявилась проблема, когда пикер находится в dbc Modal.
Что происходит на самом деле
Корень проблемы — баг с перехватом фокуса. Модальное окно настолько жёстко удерживает фокус внутри себя, что dropdown пикера не может его «зацепить», и панель времени сразу сворачивается. Это заметно как быстрый всплеск или двойное открытие‑закрытие при взаимодействии с часами и минутами.
Показательно, что тот же пикер корректно работает внутри dmc.Modal. Такой контраст указывает именно на обработку фокуса на уровне модального окна, а не на внутреннюю логику самого пикера.
Решение
Отключите принудительное удержание фокуса в Bootstrap‑модалке. Тогда она перестанет отбирать фокус у dropdown DateTimePicker, и панель времени будет оставаться открытой и интерактивной.
enforceFocus — если True, модальное окно не позволит фокусу покидать Modal, пока оно открыто.
from dash import Dash
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
web_app = Dash(name=__name__)
web_app.layout = dmc.MantineProvider([
    dbc.Modal(
        dmc.DateTimePicker(
            timePickerProps={
                'withDropdown': True,
                'popoverProps': {'withinPortal': False},
            },
        ),
        is_open=True,
        enforceFocus=False,
    ),
])
 
if __name__ == '__main__':
    web_app.run(debug=True, port=8080)
После этой правки выпадающий список времени открывается и остаётся открытым, как при выборе даты, так и при клике по области времени.
Почему это важно
Крупные приложения Dash часто комбинируют библиотеки компонентов, закрывая функциональные пробелы — например, выбор даты и времени. Когда встречаются разные экосистемы, дефолтные поведения вроде «ловушки» фокуса в модалках могут конфликтовать с интерактивными элементами — поповерами и выпадающими списками. Знание, как ослабить правила фокусировки, позволяет не устраивать переписывание и точечно подключить нужный компонент.
Если странности сохраняются, загляните в DevTools: убедитесь, что нет ошибок JavaScript, и посмотрите, как переключаются соответствующие HTML‑ и CSS‑элементы при открытии dropdown.
Выводы
Если выпадающий список времени в dmc DateTimePicker не открывается внутри dbc Modal, виновато принудительное удержание фокуса. Отключите его через enforceFocus=False, оставьте текущую настройку Mantine поповера withinPortal=False — и элемент начнёт работать штатно. Эта небольшая корректировка возвращает ожидаемый пользовательский опыт без замены модального фреймворка и без рефакторинга всего приложения.
Статья основана на вопросе на StackOverflow от Thomas и ответе EricLavault.