How to Implement Dark and Light Modes in Hyvä Using Tailwind and Alpine.js
- February 27, 2025
- Category: Hyva
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.
Conclusion:
Implementing dark mode in your Magento Hyvä store with Tailwind CSS and Alpine.js is both simple and effective. Not only does it enhance user experience by reducing eye strain and improving battery efficiency, but it also adds a modern, sleek aesthetic to your site. By following these steps, you can offer your users a seamless light and dark mode toggle, improving accessibility and engagement.
Transform Your Magento Store with Ease!
If you need expert assistance in optimizing your Magento store with Hyvä, Tailwind CSS, and Alpine.js, our team is here to help! Contact us today to take your e-commerce experience to the next level.