Closed sazzer closed 2 years ago
In fact, I can see from a quick look that the JavaScript is using DOMContentLoaded
and document.querySelectorAll
, so it is exactly binding to only the HTML that was present after the DOM first loaded.
Which means that any time the page is updated after first render - e.g. in my case when I get an API response - then the Flowbite JavaScript has already run and won't see it.
I believe the correct way to handle this is with MutationObservers, but I'm not entirely sure how well that works.
Is there a solution?
I seem to have the same issue with tooltip components. I have a page with some tabs. The tabs name have tooltip which always work Inside the tabs, the tooltip work if i refresh the page, but if i got to another tab and come back, it won't work (but the tooltips of the tab menu themselves do work)
@zoltanszogyenyi Any update to this issue? It's starting to affect a lot of developers and I'm about to migrate my projects from Flowbite to something that works.
Hey @brianshimkus,
We're preparing a standalone React component library after Monday.
The problem is that the event listeners aren't updating after the virtual DOM change.
An alternative would be to couple Flowbite with Headless UI or write the functionality yourself.
We expect a launch in the next few months in Q2 and that should make every interactive component fully compatible with React and Next.js.
We're doing our absolute best to keep up with the demand for new technologies.
I just implemented the accordion from Headless UI and it works great.
I just implemented the accordion from Headless UI and it works great.
Hey what was the workaround here?
My situation is that I'm using Tailwind 3.x + React. I have a button with a tooltip, which works, but as soon as the button is removed and later added back and rendered, the tooltip no longer works. I'd be happy to manually call a function to re-initialize the listener, but I don't see this in the docs.
Edit: here's my dirty workaround
let ev = document.createEvent("Event");
ev.initEvent("DOMContentLoaded", true, true);
window.document.dispatchEvent(ev);
This seems to be duplicate of https://github.com/themesberg/flowbite/issues/98
Is there any solution for this?
@hubsmoke Hey bro, may I know how to use the solution posted by you? How it works?
This affects more than just dropdowns. It looks like most if not all of the components use DOMContentLoaded
event to trigger these components into existence.
This affects more than just dropdowns. It looks like most if not all of the components use
DOMContentLoaded
event to trigger these components into existence.
Have you given Headless UI a try? It worked like a charm for me.
Hey everyone!
We have recently started working on a standalone Flowbite React library on Github and we are getting pretty close to finishing it. We still need some help with a few components and if you'd like, you could fork one of the issues and help us out.
After that, the whole React + Next.js compatibility issue will be solved indefinitely.
I'm having a similar issue using Flowbite in my Vue3 application. Tooltips don't work in case elements are dynamically initialized after the page is rendered.
Another scenario where I'm experiencing this issue is when used with Storybooks. After refreshing the page, tooltip works. But if I switch to a different story (page isn't fully reloaded) tooltip no longer shows up.
Hi @zoltanszogyenyi, I would please like to find out if the standalone Flowbite React is now ready. Kind Regards
Hey @agkayster,
It's still in WIP, but most of the components are ready:
add the below code to your component
const evt = new Event("DOMContentLoaded", { bubbles: true, cancelable: false });
document.dispatchEvent(evt);
Calling the below in the mounted()
hook of the Vue component will work. This is not the clean way as it ends up creating duplicate instances of tooltips if the DOM was present before DOMContentLoaded
event is triggered.
const VueComponent = {
mounted() {
document.querySelectorAll('[data-tooltip-target]').forEach(function (triggerEl) {
const targetEl = document.getElementById(triggerEl.getAttribute('data-tooltip-target'));
const triggerType = triggerEl.getAttribute('data-tooltip-trigger');
const placement = triggerEl.getAttribute('data-tooltip-placement');
new Tooltip(targetEl, triggerEl, {
placement: placement ? placement : 'top',
triggerType: triggerType ? triggerType : 'hover'
});
});
}
}
add the below code to your component
const evt = new Event("DOMContentLoaded", { bubbles: true, cancelable: false }); document.dispatchEvent(evt);
Do you mind showing how you add this to the component? I've tried to add this in useEffect in the component, but it doesn't seem to work.
add the below code to your component
const evt = new Event("DOMContentLoaded", { bubbles: true, cancelable: false }); document.dispatchEvent(evt);
Do you mind showing how you add this to the component? I've tried to add this in useEffect in the component, but it doesn't seem to work.
i am having same issue
Lo que hice en Vue fue crear una directiva en la raíz de la configuración de Vue. De esta manera, cada vez que se renderiza un elemento y ese elemento implementa la directiva, se reinicializa Flowbite.
app.directive('flowbite', {
mounted(el) {
setTimeout(() => initFlowbite(), 1500);
},
});
En este código, he creado la directiva 'flowbite' y he definido la función mounted que se ejecutará cuando el elemento con la directiva se monte en el DOM. Dentro de esta función, he utilizado setTimeout para esperar 1500 milisegundos y luego llamar a initFlowbite() para reinicializar Flowbite.
De esta manera, cada vez que se renderice un elemento con la directiva 'flowbite', se ejecutará la función mounted y se reinicializará Flowbite después de 1500 milisegundos.
Y por ejemplo en la parte del componente:
<tr v-for="model in models" :key="model.id" v-flowbite class="border-b dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700">
Esto es para Vue, pero espero les pueda ayudar para React. Saludos
The standalone react components aren't a real solution because they are extremely hard to customize, not all properties are exposed and not all tailwind classes are accepted (As Flowbite doesn't include the whole of tailwind css but only a smaller part)
In index.jsx, remove "import ReactDOM from 'react-dom/client';
" and replace it with "import ReactDOM from 'react-dom';
". This solved my issue.
Related Stack Overflow answer: https://stackoverflow.com/a/72667405/17476759
i'am using vue js but maybe there's someone who will find this useful. you see, iam using "watch" in the App.vue to watch the changes in the element or data, so whenever the data changes it will trigger the function to "recall" the flowbite cdn script, so that all the function can work again.
here is the example :
watch :{ dataToken: function(){ let recaptchaScript = document.createElement('script'); recaptchaScript.setAttribute('src', 'https://unpkg.com/flowbite@1.5.1/dist/flowbite.js'); recaptchaScript.setAttribute("id", "script-flowbite"); document.head.appendChild(recaptchaScript); }, },
put the code above to before or after mounted() in the script section.
in this case, i use "watch" to look the changes in the "dataToken" value, it contain the jwt token or something similar, so whenever the user login or logout, the script will re-appeared.
the cons : the script caller element in the head tag will increased infinitely if the user login and logout repeately without reload or re-open their browser.
so you can create element remover to remove the previous script before adding the new one.
put this code before the "add new element" script :
const scriptFlowBite = document.getElementById("script-flowbite"); scriptFlowBite.remove();
so the code will be like this :
watch :{ dataToken: function(){ const scriptFlowBite = document.getElementById("script-flowbite"); scriptFlowBite.remove(); let recaptchaScript = document.createElement('script'); recaptchaScript.setAttribute('src', 'https://unpkg.com/flowbite@1.5.1/dist/flowbite.js'); recaptchaScript.setAttribute("id", "script-flowbite"); document.head.appendChild(recaptchaScript); } },
don't forget to add the id in the first script call to make sure the script can get deleted and added again, in my case i put my first script call in the mounted(){ }. hope this can help someone.
Estuve revisando porque tuve el mismo problema porque al dar F5 servia nuevamente los dropdown y encontré una solución para VUE 3, creando un plugin flowbite.js para que cada vez que cambie de ruta se reinicialice:
//main.js
....
import flowbitePlugin from '@/plugins/flowbite';
...
app.use(router)
.use(flowbitePlugin);
app.mount('#app');
//src/plugins/flowbite.js
import { initFlowbite } from 'flowbite';
export default {
install(app) {
app.mixin({
mounted() {
initFlowbite(); // Inicializa Flowbite en el montaje del componente
},
watch: {
$route() {
initFlowbite(); // Re-inicializa Flowbite cuando cambia la ruta
}
}
});
}
};
//Asegurarse make sure - que en el index.html este importado el js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/flowbite@1.4.5/dist/flowbite.js"></script>
<title>Title</title>
</head>
<body class="bg-gray-50 dark:bg-gray-800">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Estuve revisando porque tuve el mismo problema porque al dar F5 servia nuevamente los dropdown y encontré una solución para VUE 3, creando un plugin flowbite.js para que cada vez que cambie de ruta se reinicialice:
//main.js
.... import flowbitePlugin from '@/plugins/flowbite'; ... app.use(router) .use(flowbitePlugin); app.mount('#app');
//src/plugins/flowbite.js
import { initFlowbite } from 'flowbite'; export default { install(app) { app.mixin({ mounted() { initFlowbite(); // Inicializa Flowbite en el montaje del componente }, watch: { $route() { initFlowbite(); // Re-inicializa Flowbite cuando cambia la ruta } } }); } };
//Asegurarse make sure - que en el index.html este importado el js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/flowbite@1.4.5/dist/flowbite.js"></script> <title>Title</title> </head> <body class="bg-gray-50 dark:bg-gray-800"> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body> </html>
Wow this solved it for me. The tooltip was not appearing for elements that were dynamically initialized after the page is rendered. Adding the initFlowbite() call to onMounted hook of the dynamically rendered elements solved it for me. Thanks
Describe the bug When using Flowbite with React, if the page updates after first load to include a dropdown that wasn't originally present then the dropdown doesn't open when clicked.
I assume this applies to all JavaScript but I've not tried any others yet.
There are no console errors and nothing obvious at all in any logs. It just only ever works if the Dropdown HTML was present in the first render, and doesn't work if it was only present after an update.
My assumption is that the event listeners are bound to the HTML as it is when the JavaScript first runs, and doesn't use any mechanism to bind to changes that happen later.
Desktop (please complete the following information):