Dark mode is no longer just a trend, it’s an essential feature for providing an enhanced user experience. With Magento Hyvä, Tailwind CSS and Alpine.js this functionality becomes simple and elegant. In this blog, we will explore how to implement a seamless dark and light mode switch.
Why Dark Mode Matters
Dark mode not only looks stylish but also reduces eye strain, especially in low-light environments. It improves battery efficiency on OLED screens and gives users the freedom to choose their preferred visual style. Tailwind CSS, with its utility-first approach, and Alpine.js, known for lightweight interactivity, make the perfect combo for this implementation. To make this as easy as possible, Tailwind includes a dark variant that lets you style your site differently when dark mode is enabled.Step-by-Step Guide to Implement Dark and Light Mode in Hyva
Prerequisites: Ensure you have a working Magento 2 store with the Hyva theme.1. Update tailwind.config.js
File Path: app/design/frontend/<Vendor>/<Theme>/web/tailwind/tailwind.config.js To enable dark mode in Tailwind, configure the darkMode setting:module.exports = { darkMode: 'selector', theme: { extend: {}, }, plugins: [], };
2. Add Design Content with Light and Dark Modes in PHTML file
<div x-data="{darkMode: false}" :class="{'dark': darkMode === true }" class="container antialiased"> <button @click="darkMode=!darkMode; document.body.classList.toggle('bg-slate-800', darkMode)" type="button" class="relative inline-flex flex-shrink-0 h-7 my-5 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer bg-zinc-200 dark:bg-zinc-700 w-12" role="switch" aria-checked="false"> <span class="sr-only">Use setting</span> <span class="relative inline-block w-6 h-6 transition duration-500 ease-in-out transform translate-x-0 bg-white rounded-full shadow pointer-events-none dark:translate-x-5 ring-0"> <span class="absolute inset-0 flex items-center justify-center w-full h-full transition-opacity duration-500 ease-in opacity-100 dark:opacity-0 dark:duration-100 dark:ease-out" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> <path fill="#FFAC33" d="M16 2s0-2 2-2 2 2 2 2v2s0 2-2 2-2-2-2-2zm18 14s2 0 2 2-2 2-2 2h-2s-2 0-2-2 2-2 2-2zM4 16s2 0 2 2-2 2-2 2H2s-2 0-2-2 2-2 2-2zm5.121-8.707s1.414 1.414 0 2.828-2.828 0-2.828 0L4.878 8.708s-1.414-1.414 0-2.829c1.415-1.414 2.829 0 2.829 0zm21 21s1.414 1.414 0 2.828-2.828 0-2.828 0l-1.414-1.414s-1.414-1.414 0-2.828 2.828 0 2.828 0zm-.413-18.172s-1.414 1.414-2.828 0 0-2.828 0-2.828l1.414-1.414s1.414-1.414 2.828 0 0 2.828 0 2.828zm-21 21s-1.414 1.414-2.828 0 0-2.828 0-2.828l1.414-1.414s1.414-1.414 2.828 0 0 2.828 0 2.828zM16 32s0-2 2-2 2 2 2 2v2s0 2-2 2-2-2-2-2z"/> <circle fill="#FFAC33" cx="18" cy="18" r="10"/> </svg> </span> <span class="absolute inset-0 flex items-center justify-center w-full h-full transition-opacity duration-100 ease-out opacity-0 dark:opacity-100 dark:duration-200 dark:ease-in" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M2.03 12.42c.36 5.15 4.73 9.34 9.96 9.57 3.69.16 6.99-1.56 8.97-4.27.82-1.11.38-1.85-.99-1.6-.67.12-1.36.17-2.08.14C13 16.06 9 11.97 8.98 7.14c-.01-1.3.26-2.53.75-3.65.54-1.24-.11-1.83-1.36-1.3C4.41 3.86 1.7 7.85 2.03 12.42" stroke="#292D32" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </span> </span> </button> <div class="my-12 mx-auto rounded-lg border border-gray-200 md:p-11 p-5"> <div class="flex flex-wrap -mx-1 lg:-mx-4"> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> <div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3"> <article class="rounded-lg shadow-md dark:bg-slate-700"> <div class="flex items-center justify-between p-2 md:p-4"> <h1 class="text-lg"> <a class="no-underline hover:underline text-black dark:text-slate-300" href="#"> Article Title </a> </h1> <p class="text-grey-darker dark:text-slate-300 text-sm"> 11/1/19 </p> </div> <div class="flex items-center justify-between leading-none p-2 md:p-4"> <a class="flex items-center no-underline hover:underline text-black dark:text-slate-300" href="#"> <?= $heroicons->userCircleHtml('text-gray-700 dark:text-slate-300', 24, 24) ?> <p class="ml-2 text-sm"> Author Name </p> </a> </div> </article> </div> </div> </div> </div>
x-data="{darkMode: false}":
Initializes Alpine.js state variable darkMode set to false- @click: Toggles darkMode on button click and adds/removes the dark-mode class on the document.body .
:class="{'dark': darkMode}``:
Dynamically applies the dark class to the container based on the darkMode value.- Button design includes Tailwind classes for switch button design.
3. After making the necessary changes, run the following command to build your Tailwind CSS
bin/magento cache:clean
in your root directory
npm run build-prod in your theme directory - app/design/frontend/<Vendor>/<Theme>/web/tailwind/
For more information, refer to the official Tailwind CSS - Dark Mode Documentation.