In this tutorial, Today I will explain How to Create A Fixed Header on Scroll using AlpineJs and Tailwind CSS in Hyva Magento 2 using TailwindCSS and AlpineJS.
You just add below code in your any PHTML file.
<div x-data="{scrolAtTop: true}">
<div class="w-full"
:class="{ 'theme-bg-grey6 fixed top-0 z-20 shadow-md': !scrolAtTop }"
@scroll.window="scrolAtTop = (window.pageYOffset > 200) ? false : true"
>
Test Content
</div>
</div>
In hyva theme you need to just copy below code and paste in header.phtml file
<?php
/**
* Hyvä Themes - https://hyva.io
* Copyright © Hyvä Themes 2020-present. All rights reserved.
* This product is licensed per Magento install
* See https://hyva.io/license
*/
declare(strict_types=1);
use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\HeroiconsOutline;
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;
/** @var Escaper $escaper */
/** @var Template $block */
/** @var ViewModelRegistry $viewModels */
/** @var HeroiconsOutline $heroicons */
$heroicons = $viewModels->require(HeroiconsOutline::class);
/** @var Hyva\Theme\ViewModel\StoreConfig $storeConfig */
$storeConfig = $viewModels->require(Hyva\Theme\ViewModel\StoreConfig::class);
$showMiniCart = $storeConfig->getStoreConfig(\Magento\Checkout\Block\Cart\Sidebar::XML_PATH_CHECKOUT_SIDEBAR_DISPLAY)
?>
<script>
function initHeader () {
return {
searchOpen: false,
cart: {},
getData(data) {
if (data.cart) { this.cart = data.cart }
},
menu: initHeaderNavigation()
}
}
function initCompareHeader() {
return {
compareProducts: null,
itemCount: 0,
receiveCompareData(data) {
if (data['compare-products']) {
this.compareProducts = data['compare-products'];
this.itemCount = this.compareProducts.count;
}
}
}
}
</script>
<div x-data="{scrolAtTop: true}">
<div class="w-full"
:class="{ 'theme-bg-grey6 fixed top-0 z-20 shadow-md': !scrolAtTop }"
@scroll.window="scrolAtTop = (window.pageYOffset > 200) ? false : true"
>
<nav id="header"
class="z-30 w-full border-b shadow bg-container-lighter border-container-lighter"
x-data="initHeader()"
@keydown.window.escape="searchOpen = false;"
@private-content-loaded.window="getData(event.detail.data)"
>
<div class="container flex flex-wrap items-center justify-between w-full px-6 py-3 mx-auto mt-0">
<!--Logo-->
<?= $block->getChildHtml('logo'); ?>
<!--Main Navigation-->
<?= $block->getChildHtml('topmenu') ?>
<div class="flex items-center order-3">
<!--Compare Icon-->
<a id="compare-link"
class="relative invisible inline-block mx-1 no-underline sm:ml-3 hover:text-black"
:class="{ 'invisible': !(itemCount > 0) }"
href="<?= $escaper->escapeUrl($block->getUrl('catalog/product_compare/index')) ?>"
title="<?= $escaper->escapeHtml(__('Compare Products')) ?>"
x-data="initCompareHeader()"
@private-content-loaded.window="receiveCompareData($event.detail.data)"
>
<?= $heroicons->scaleHtml(
"w-8 h-8 md:h-6 md:w-6 hover:text-black",
25,
25
) ?>
<span class="sr-only label">
<?= $escaper->escapeHtml(__('Compare Products')) ?>
</span>
<span class="absolute top-0 right-0 h-5 px-2 py-1 -mt-5 -mr-4 text-xs font-semibold
leading-none text-center text-white uppercase transform -translate-x-1
translate-y-1/2 bg-yellow-500 rounded-full"
>
<span x-text="itemCount"></span>
<span x-show="itemCount === 1" class="sr-only">
<?= $escaper->escapeHtml(__('item')) ?>
</span>
<span x-show="itemCount > 1" class="sr-only">
<?= $escaper->escapeHtml(__('items')) ?>
</span>
</span>
</a>
<!--Search Icon-->
<a id="menu-search-icon"
class="inline-block ml-1 no-underline sm:ml-3 hover:text-black"
href="#"
@click.prevent="searchOpen = !searchOpen; $nextTick(function () { document.querySelector('#search').select(); });"
>
<span class="sr-only label">
<?= $escaper->escapeHtml(__('Search')) ?>
</span>
<?= $heroicons->searchHtml(
"w-8 h-8 md:h-6 md:w-6 hover:text-black",
25,
25
) ?>
</a>
<!--Customer Icon & Dropdown-->
<?= $block->getChildHtml('customer') ?>
<!--Cart Icon-->
<a id="menu-cart-icon"
<?php if ($showMiniCart): ?>@click.prevent.stop="$dispatch('toggle-cart',{});"<?php endif ?>
class="relative inline-block ml-1 no-underline sm:ml-3 hover:text-black"
href="<?= $escaper->escapeUrl($block->getUrl('checkout/cart/index')) ?>"
>
<span class="sr-only label">
<?= $escaper->escapeHtml(__('Cart')) ?>
</span>
<?= $heroicons->shoppingCartHtml(
"w-8 h-8 md:h-6 md:w-6 hover:text-black",
25,
25
) ?>
<span x-text="cart.summary_count"
class="absolute top-0 right-0 hidden h-5 px-2 py-1 -mt-5 -mr-4 text-xs font-semibold
leading-none text-center text-white uppercase transform -translate-x-1
translate-y-1/2 rounded-full bg-primary"
:class="{
'hidden': !cart.summary_count,
'block': cart.summary_count }"
></span>
</a>
</div>
</div>
<!--Search-->
<div class="absolute z-10 hidden w-full border-t shadow-sm bg-container-lighter border-container-lighter"
id="search-content"
:class="{ 'block': searchOpen, 'hidden': !searchOpen }"
@click.away="searchOpen = false"
x-show="true"
>
<?= $block->getChildHtml('header-search'); ?>
</div>
<!--Cart Drawer-->
<?= $block->getChildHtml('cart-drawer'); ?>
<!--Authentication Pop-Up-->
<?= $block->getChildHtml('authentication-popup'); ?>
</nav>
</div>
</div>
See example how it’s work:

I hope this blog is easy to understand about How to Create A Fixed Header on Scroll in Hyva Magento 2 using TailwindCSS and AlpineJS. In case, I missed anything or need to add some information, always feel free to leave a comment in this blog, I’ll get back with proper solution.
Keep liking and sharing !!
More will be coming soon… 🙂
[…] easy to get spaghetti (here is an example of a Magento theme header). You can end up adding a lot of content into an HTML attribute. This ends up being really […]
LikeLike