diff --git a/.changeset/defer-data-api-init-to-dom-content-loaded.md b/.changeset/defer-data-api-init-to-dom-content-loaded.md new file mode 100644 index 000000000..1b4f5fc6b --- /dev/null +++ b/.changeset/defer-data-api-init-to-dom-content-loaded.md @@ -0,0 +1,5 @@ +--- +"@tabler/core": patch +--- + +Fixed tab, tooltip, popover, dropdown and toast init running before `DOMContentLoaded`, dropping early listeners. diff --git a/core/js/src/dropdown.ts b/core/js/src/dropdown.ts index 104c2a896..39bbbde43 100644 --- a/core/js/src/dropdown.ts +++ b/core/js/src/dropdown.ts @@ -1,15 +1,18 @@ import { Dropdown } from './bootstrap' import Manipulator from './bootstrap/dom/manipulator' +import { onDOMContentLoaded } from './bootstrap/util/index' // js-docs-start dropdown-init -for (const dropdownTriggerEl of document.querySelectorAll('[data-bs-toggle="dropdown"], [data-tblr-toggle="dropdown"]')) { - try { - const options = { - boundary: Manipulator.getDataAttribute(dropdownTriggerEl, 'boundary') === 'viewport' ? document.documentElement : ('clippingParents' as const), +onDOMContentLoaded(() => { + for (const dropdownTriggerEl of document.querySelectorAll('[data-bs-toggle="dropdown"], [data-tblr-toggle="dropdown"]')) { + try { + const options = { + boundary: Manipulator.getDataAttribute(dropdownTriggerEl, 'boundary') === 'viewport' ? document.documentElement : ('clippingParents' as const), + } + Dropdown.getOrCreateInstance(dropdownTriggerEl, options) + } catch (error) { + console.error(error) } - Dropdown.getOrCreateInstance(dropdownTriggerEl, options) - } catch (error) { - console.error(error) } -} +}) // js-docs-end dropdown-init diff --git a/core/js/src/popover.ts b/core/js/src/popover.ts index a3bd66f05..1f55c2ab8 100644 --- a/core/js/src/popover.ts +++ b/core/js/src/popover.ts @@ -1,16 +1,19 @@ import { Popover } from './bootstrap' import Manipulator from './bootstrap/dom/manipulator' +import { onDOMContentLoaded } from './bootstrap/util/index' // js-docs-start popover-init -for (const popoverTriggerEl of document.querySelectorAll('[data-bs-toggle="popover"], [data-tblr-toggle="popover"]')) { - try { - const options = { - delay: Manipulator.getDataAttribute(popoverTriggerEl, 'delay') ?? { show: 50, hide: 50 }, - placement: Manipulator.getDataAttribute(popoverTriggerEl, 'placement') ?? 'auto', +onDOMContentLoaded(() => { + for (const popoverTriggerEl of document.querySelectorAll('[data-bs-toggle="popover"], [data-tblr-toggle="popover"]')) { + try { + const options = { + delay: Manipulator.getDataAttribute(popoverTriggerEl, 'delay') ?? { show: 50, hide: 50 }, + placement: Manipulator.getDataAttribute(popoverTriggerEl, 'placement') ?? 'auto', + } + Popover.getOrCreateInstance(popoverTriggerEl, options) + } catch (error) { + console.error(error) } - Popover.getOrCreateInstance(popoverTriggerEl, options) - } catch (error) { - console.error(error) } -} +}) // js-docs-end popover-init diff --git a/core/js/src/tab.ts b/core/js/src/tab.ts index 380d84176..d5e996ffb 100644 --- a/core/js/src/tab.ts +++ b/core/js/src/tab.ts @@ -1,4 +1,5 @@ import { Tab } from './bootstrap' +import { onDOMContentLoaded } from './bootstrap/util/index' // js-docs-start tab-init export const EnableActivationTabsFromLocationHash = (): void => { @@ -23,5 +24,5 @@ export const EnableActivationTabsFromLocationHash = (): void => { } } -EnableActivationTabsFromLocationHash() +onDOMContentLoaded(EnableActivationTabsFromLocationHash) // js-docs-end tab-init diff --git a/core/js/src/toast.ts b/core/js/src/toast.ts index 77a196342..1e27ceb24 100644 --- a/core/js/src/toast.ts +++ b/core/js/src/toast.ts @@ -1,22 +1,25 @@ import { Toast } from './bootstrap' import SelectorEngine from './bootstrap/dom/selector-engine' +import { onDOMContentLoaded } from './bootstrap/util/index' // js-docs-start toast-init -for (const toastTriggerEl of document.querySelectorAll('[data-bs-toggle="toast"], [data-tblr-toggle="toast"]')) { - try { - // A trigger whose target is missing is left alone instead of getting a - // click handler that throws. - const toastEl = SelectorEngine.getElementFromSelector(toastTriggerEl) - if (!toastEl) { - continue - } +onDOMContentLoaded(() => { + for (const toastTriggerEl of document.querySelectorAll('[data-bs-toggle="toast"], [data-tblr-toggle="toast"]')) { + try { + // A trigger whose target is missing is left alone instead of getting a + // click handler that throws. + const toastEl = SelectorEngine.getElementFromSelector(toastTriggerEl) + if (!toastEl) { + continue + } - const toast = Toast.getOrCreateInstance(toastEl) as InstanceType - toastTriggerEl.addEventListener('click', () => { - toast.show() - }) - } catch (error) { - console.error(error) + const toast = Toast.getOrCreateInstance(toastEl) as InstanceType + toastTriggerEl.addEventListener('click', () => { + toast.show() + }) + } catch (error) { + console.error(error) + } } -} +}) // js-docs-end toast-init diff --git a/core/js/src/tooltip.ts b/core/js/src/tooltip.ts index d0345a67b..c481fd75a 100644 --- a/core/js/src/tooltip.ts +++ b/core/js/src/tooltip.ts @@ -1,19 +1,22 @@ import { Tooltip } from './bootstrap' import Manipulator from './bootstrap/dom/manipulator' +import { onDOMContentLoaded } from './bootstrap/util/index' // js-docs-start tooltip-init // One element with a broken config must not stop the rest of the bundle, so // every instance is created on its own. `data-bs-delay` on the element wins // over the shorter default delay. -for (const tooltipTriggerEl of document.querySelectorAll('[data-bs-toggle="tooltip"], [data-tblr-toggle="tooltip"]')) { - try { - const options = { - delay: Manipulator.getDataAttribute(tooltipTriggerEl, 'delay') ?? { show: 50, hide: 50 }, - placement: Manipulator.getDataAttribute(tooltipTriggerEl, 'placement') ?? 'auto', +onDOMContentLoaded(() => { + for (const tooltipTriggerEl of document.querySelectorAll('[data-bs-toggle="tooltip"], [data-tblr-toggle="tooltip"]')) { + try { + const options = { + delay: Manipulator.getDataAttribute(tooltipTriggerEl, 'delay') ?? { show: 50, hide: 50 }, + placement: Manipulator.getDataAttribute(tooltipTriggerEl, 'placement') ?? 'auto', + } + Tooltip.getOrCreateInstance(tooltipTriggerEl, options) + } catch (error) { + console.error(error) } - Tooltip.getOrCreateInstance(tooltipTriggerEl, options) - } catch (error) { - console.error(error) } -} +}) // js-docs-end tooltip-init diff --git a/docs/content/ui/components/tab.mdx b/docs/content/ui/components/tab.mdx index dd134dcf5..3ac2e2b2b 100644 --- a/docs/content/ui/components/tab.mdx +++ b/docs/content/ui/components/tab.mdx @@ -233,6 +233,8 @@ Tabler activates the tab that matches the URL hash on page load, so you can link +This runs on `DOMContentLoaded`, so `show.bs.tab` and `shown.bs.tab` for the hash tab fire before any script that itself waits for `DOMContentLoaded`. Add the listener earlier (a plain `