2

Always I reload any page happens a quick flash that changes the entire system to dark mode and comes back again, but really quick.

Before, this was happens also on dark mode too, but I could fix it loading the function that loads the themes on head of the HTML. Therefore, this doesn't work in light mode, and I have no idea why.

We are using Thymeleaf (from Java), idk if it changes anything, and also HTML, Tailwind CSS, and JS. I'm going to put the file code here which is the all pages template that it happens.

(function() {
  const docElement = document.documentElement;

  const cookieMatch = document.cookie.match(/theme=(dark|light)/);
  const savedTheme = cookieMatch ? cookieMatch[1] : null;

  const themeToApply = savedTheme || 'light';

  if (themeToApply === 'dark') {
    docElement.classList.add('dark');
  } else {
    docElement.classList.remove('dark');
  }

  if (window.innerWidth >= 1024) {
    const sidebarMatch = document.cookie.match(/sidebarState=(true|false)/);
    const sidebarOpen = sidebarMatch ? sidebarMatch[1] === 'true' : true;

    if (!sidebarOpen) {
      docElement.classList.add('sidebar-closed');
    } else {
      docElement.classList.remove('sidebar-closed');
    }
  } else {
    docElement.classList.add('sidebar-closed');
  }
})();


tailwind.config = {
    darkMode: 'class',
    theme: {
      extend: {
        // extensões de tema
      }
    }
  }
  
  function layout() {
    return {
      isSidebarOpen: window.innerWidth >= 1024 ?
        !document.documentElement.classList.contains('sidebar-closed') : false,

      theme: (document.cookie.match(/theme=(dark|light)/) || [null, 'light'])[1],

      oneYearInSeconds: 365 * 24 * 60 * 60,

      init() {
        this.$watch('theme', (newTheme) => {
          if (newTheme === 'dark') {
            document.documentElement.classList.add('dark');
          } else {
            document.documentElement.classList.remove('dark');
          }

          document.cookie = `theme=${newTheme}; path=/; max-age=${this.oneYearInSeconds}`;
        });

        this.$watch('isSidebarOpen', (isOpen) => {
          if (!isOpen) {
            document.documentElement.classList.add('sidebar-closed');
          } else {
            document.documentElement.classList.remove('sidebar-closed');
          }
        });

        window.addEventListener('resize', () => {
          if (window.innerWidth < 1024) {
            this.isSidebarOpen = false;
          }
        });
      },

      toggleSidebar() {
        this.isSidebarOpen = !this.isSidebarOpen;

        if (window.innerWidth >= 1024) {
          document.cookie = `sidebarState=${this.isSidebarOpen}; path=/; max-age=${this.oneYearInSeconds}`;
        }
      },

      closeSidebarOnMobile() {
        if (window.innerWidth < 1024) {
          this.isSidebarOpen = false;
        }
      },

      toggleTheme() {
        this.theme = (this.theme === 'light' ? 'dark' : 'light');
      }
    }
  }
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>

<link href="https://cdn.datatables.net/2.0.8/css/dataTables.tailwindcss.css" rel="stylesheet">

<script src="https://code.jquery.com/jquery-3.7.1.js"></script>

<script src="https://cdn.datatables.net/2.0.8/js/dataTables.js"></script>
<script src="https://cdn.datatables.net/2.0.8/js/dataTables.tailwindcss.js"></script>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />

<body class="flex flex-col min-h-screen bg-neutral-50 dark:bg-zinc-800 overflow-x-hidden" x-data="layout()">

  <header class="w-full z-20 sticky top-0 left-0 right-0 bg-white shadow border-b border-gray-200">
    <div th:replace="~{layouts/header :: header}"></div>
  </header>

  <div class="flex lg:flex-row flex-col">
    <div th:replace="~{layouts/sidebar :: sidebar}"></div>

    <!-- Overlay para mobile quando sidebar está aberta -->
    <div x-show="isSidebarOpen && window.innerWidth < 1024" @click="toggleSidebar()" x-transition:enter="transition-opacity ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition-opacity ease-in duration-200" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" class="fixed inset-0 bg-black bg-opacity-50 z-30 lg:hidden" style="display: none;">
    </div>

    <div class="flex-1 flex flex-col min-h-0 p-0 pt-6 w-dvw pl-64" :class="{'pl-20': !isSidebarOpen}">
      <main class="flex-1 p-0 pt-0 mr-6 ml-8">
        <div class="mx-auto mb-6 flex justify-between items-center">
          <div th:replace="~{fragments/breadcrumb :: breadcrumb}"></div>

          <div class="flex items-center z-20">
            <a href="#" class="group flex items-center text-sm font-semibold leading-6">
                        <span class="mx-2"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="h-5 w-5 text-neutral-900 dark:text-gray-200"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></span>
                    </a>
            <div th:replace="~{fragments/profile_button_thymeleaf :: userProfileDropdown}"></div>
          </div>
        </div>
        <div th:insert="~{this :: content}" th:remove="tag"></div>

        <!-- Fixed toast container (top-right) for FlashMessageHelper messages -->
        <div class="fixed top-5 right-5 z-50 space-y-2" id="flash-toast-container">
          <div th:if="${!#lists.isEmpty(errors)}" th:insert="~{fragments/alert :: messages(${errors})}"></div>
          <div th:if="${!#lists.isEmpty(infos)}" th:insert="~{fragments/alert :: messages(${infos})}"></div>
          <div th:if="${!#lists.isEmpty(success)}" th:insert="~{fragments/alert :: messages(${success})}"></div>
        </div>

      </main>
    </div>
  </div>
  <div th:insert="~{this :: scripts}" th:remove="tag"></div>
</body>

New contributor
Samuel Franklin is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
2

2 Answers 2

4

I suspect this because you load the cdn.tailwindcss before the config.

# Tailwind config MUST be before the CDN
<script>
    window.tailwind = {
        config: {
            darkMode: 'class',
            theme: {
                extend: {
                    // extensões de tema
                }
            }
        }
    }
</script>

# Now load Tailwind
<script src="https://cdn.tailwindcss.com"></script>

Configuration

Sign up to request clarification or add additional context in comments.

Comments

2

Although Abdulla Nilam mentioned the correct answer - that the issue was caused by using the Tailwind Play CDN - I suggest that even though you've solved the problem, you should still avoid using the Play CDN.

Use the Play CDN to try Tailwind right in the browser without any build step. The Play CDN is designed for development purposes only, and is not intended for production. (reference)

TailwindCSS is a development tool. The Play CDN exists solely for creating quick reproductions, but it's absolutely the wrong approach to use it in a real production application:

  • If the CDN becomes unavailable (for example, Cloudflare recently had an incident), your app will go down until it comes back (potentially for several hours).
  • On every load, the Tailwind engine unnecessarily rebuilds the exact same CSS that it already built the previous 1000, 2000, 3000 times - completely wasted work.

If you don't have the option to ship a frontend with PostCSS or Vite, then simply use the Tailwind CLI solution. During development, with watch mode, it updates the CSS files instantly just like the Play CDN would. But in production, you only need to deliver the final compiled CSS without Tailwind itself, sparing your website from loading Tailwind unnecessarily.

You don't have the option to use Node.js and npm? No problem. They provide executable-based CLI solutions for Windows, macOS, and Linux as well.

Here you can choose the version by downloading the appropriate executable. The documentation points to the latest version (that is, v4). If you need v3, download the executable from the corresponding release.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.