New Metronic Docs!Added Integration Docs with Starter Kits Apps for Laravel, Laravel Livewire, Angular, Vue, Symfony, Blazor Server, Django & Flask & more
Browse Docs

Accordion inside Livewire modal not working


I’m using Metronic with Laravel + Livewire, and everything works fine in general.

I have an accordion placed inside a Livewire component that renders as a modal. The issue is: when I open the modal, the built-in KTUI accordion JS does not work.

Do I need to reinitialize KTUI when the modal is opened, or is there another recommended approach to make the accordion work inside dynamically rendered modals? If I need to reinitialize KTUI, how can I do it?


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (8)


Hi Adam Nielsen

Here is one of the approaches without a timeout delay.

Use livewire built-in event.


document.addEventListener("livewire:init", function () {
// Main hook for DOM updates
Livewire.hook("morph.updated", ({ component, el }) => {
// Check if the updated element is a modal or contains a modal
const modal = el.querySelector("[data-kt-modal-initialized]") ||
(el.hasAttribute("data-kt-modal-initialized") ? el : null);

if (modal) {
const selectElements = modal.querySelectorAll("[data-kt-select]");
selectElements.forEach(el => {
// Dispose existing instance
if (el.instance) el.instance.dispose();

// Determine multiple state
const multiple = el.getAttribute("data-multiple") === "true";

// Create new instance with dynamic configuration
el.instance = new KTSelect(el, {
multiple: multiple,
displaySeparator: multiple ? " | " : undefined
});
});
}
});
});



<select
class="kt-select"
data-kt-select="true"
data-multiple="true" <!-- This will be read by the js -->


Thanks



And can I disable / enable


multiple
data-kt-select-multiple="true"
data-kt-select-config="{
"displaySeparator": " | "
}"


When I recreate it? Because if I only have one element, it makes no sense to have that multiple, but it depends on the selection of a previous select box



Hey Faizal, thanks for your suggestion. I tried that, and it seems that

const selectElements = modal.querySelectorAll("[data-kt-select]");
is always an empty nodeList. I managed to do it using


document.addEventListener("shown", () => {
setTimeout(() => {
const modal = document.querySelector("[data-kt-modal-initialized]");
const selectElements = modal.querySelectorAll("[data-kt-select]");

selectElements.forEach(el => {
if (el.instance) el.instance.dispose();
el.instance = new KTSelect(el);
});
}, 50);
});


But I am not really happy with the 50ms delay. IF you have a better suggestion please let me know.



Hi Adam Nielsen

Here's the correct solution for reinitializing KTSelect components in Livewire modals:

document.addEventListener("livewire:init", function () {
// Listen for the actual KTUI modal "shown" event
document.addEventListener("shown", function(event) {
// Check if this is a modal event
if (event.target.hasAttribute("data-kt-modal-initialized")) {
const modal = event.target;

// Find uninitialized select elements in the modal
const selectElements = modal.querySelectorAll("[data-kt-select]");

selectElements.forEach(element => {
// Check if the element already has a KTSelect instance
if (element.instance) {
// Dispose the existing instance first
element.instance.dispose();
}

// Create a new KTSelect instance
new KTSelect(element);
});
}
});
});


You need to call dispose() on the existing instance before creating a new one.
The KTSelect constructor stores the instance on the element as element.instance (line 74 in the code).
Unlike accordion, KTSelect doesn't use data attributes for initialization tracking.



Hey Faizal, this works perfect thank you.

I have the same issue with a multiple select

<select
class="kt-select"
data-kt-select="true"
data-kt-select-multiple="true"
data-kt-select-max-selections="3"
data-kt-select-placeholder="Select cities..."
data-kt-select-config="{
"displaySeparator": " | "
}"
>
<option value="amsterdam">Amsterdam</option>
<option value="barcelona">Barcelona</option>
<option value="london">London</option>
<option value="new-york">New York</option>
<option value="paris">Paris</option>
<option value="rome">Rome</option>
<option value="tokyo">Tokyo</option>
</select>


Its also in a modal that I start with livewire and I somehow need to reinit the js.

I tried a similar approach for the select, but its not working. Can you help me what I have to do here?


<div>
<x-modal :title="$edit_mode ? __("Edit AI Model") : __("Create AI Model")">
<select
class="kt-select"
data-kt-select="true"
data-kt-select-multiple="true"
data-kt-select-max-selections="3"
data-kt-select-placeholder="Select cities..."
data-kt-select-config="{
"displaySeparator": " | "
}"
>
<option value="amsterdam">Amsterdam</option>
<option value="barcelona">Barcelona</option>
<option value="london">London</option>
<option value="new-york">New York</option>
<option value="paris">Paris</option>
<option value="rome">Rome</option>
<option value="tokyo">Tokyo</option>
</select>


</x-modal>
</div>

<script>
document.addEventListener("livewire:init", function () {
console.log("init")
// Listen for the actual KTUI modal "shown" event
document.addEventListener("shown", function(event) {
if (event.target.hasAttribute("data-kt-modal-initialized")) {
const modal = event.target;

// Find uninitialized accordions in the modal
const selectboxes = modal.querySelectorAll("[data-kt-select]:not([data-kt-select-initialized])");
console.log(accordions);
selectboxes.forEach(element => {
let x = new KTSelect(element);
console.log(x);
});
}
});
});
</script>



Hi Adam Nielsen

Sorry, could you please try this code to reinitialize accordion in livewire, after opening modal?

document.addEventListener("livewire:init", function () {
// Listen for the actual KTUI modal "shown" event
document.addEventListener("shown", function(event) {
// Check if this is a modal event
if (event.target.hasAttribute("data-kt-modal-initialized")) {
const modal = event.target;

// Find uninitialized accordions in the modal
const accordions = modal.querySelectorAll("[data-kt-accordion]:not([data-kt-accordion-initialized])");

accordions.forEach(element => {
new KTAccordion(element);
});
}
});
});



Hi Adam Nielsen

Yes, you need to reinitialize KTUI components after Livewire updates the DOM.


// After Livewire updates
Livewire.hook("message.processed", (message, component) => {
// Re-initialize all KTUI components
KTComponents.init();
});


Initialize after modal open

// If using Bootstrap modals
document.addEventListener("shown.bs.modal", function(event) {
const modal = event.target;
const accordions = modal.querySelectorAll("[data-kt-accordion]");

accordions.forEach(element => {
if (!element.hasAttribute("data-kt-accordion-initialized")) {
new KTAccordion(element);
}
});
});



Hey thank you. I am using Tailwind. Unfortunately, the

Livewire.hook("message.processed", (message, component) => {
// Re-initialize all KTUI components
console.log("hallo");
KTComponents.init();
});
does not work - there is no difference if I add it or not.

To be more specific, if this is my livewire blade code


<pre lang="html">
<x-modal>
@if($user)
<x-accordion >
@endif
</x-modal>


and this is my main page:


<pre lang="html">
<div>
<livewire:modal>
</div>

@push("scripts")
<script>
document.addEventListener("DOMContentLoaded", function () {
Livewire.hook("message.processed", (message, component) => {
// Re-initialize all KTUI components
KTComponents.init();
});

</script>
@endpush


Then the modal open on click, and the user is set and then the accordion shows, but the KTUI JS (opening/close) is not working. In fact, I also see no console.log, this means the hook is never triggered. If I remove the `@if($user)` it would work, because the HTML would be there on initial page load, but thats not possible in my case. I have more of those cases, where an accordion or select element appears based on a condition and the JS is no longer working. Help appreciated.

Also, if I run init() after modal opens, is still doesn't work.


Livewire.on("open-info-modal", () => {
console.log("reinit mtgf");
KTComponents.init();
});


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(