javascripthtmllaravelalpine.js

Alpine.js menu toggle issue


I'm currently working on a project using Laravel and Alpine.js, and I've run into a bit of a problem with a menu toggle feature. I have a button that is supposed to toggle the visibility of a menu when clicked. However, the menu is not showing.

Here’s a simplified version of my code:

resources/views/test.blade.php:

<!DOCTYPE html>
<html x-data="data()">

<head>
    @vite(['resources/js/app.js'])
</head>
<body>
    <button @click="toggleMenu" @keydown.escape="closeMenu">Toggle menu</button>
    <template x-if="isMenuOpen">
        <div @click.away="closeMenu" @keydown.escape="closeMenu">Menu is open.</div>
    </template>
</body>
</html>

resources/js/app.js:

import Alpine from 'alpinejs';
window.Alpine = Alpine;
window.data = function data() {
    return {
        isMenuOpen: false,
        toggleMenu() {
            this.isMenuOpen = !this.isMenuOpen;
        },
        closeMenu() {
            this.isMenuOpen = false;
        },
    }
}
Alpine.start();

I have installed a debugbar for Alpine.js to investigate the problem. The issue seems to be that the isMenuOpen variable is set to true when I click the button, but it quickly changes back to false, causing the menu to close immediately.

Does anyone have any suggestions on how to make the menu stay open after clicking the button? Any help would be greatly appreciated!

Thanks in advance!


Solution

  • When you click the button you are also clicking outside the 'menu', so the @click.away event is triggered.

    You can use x-show instead of x-if to display/hide the menu in conjunction with x-cloak, this has a different behavior:

    <head>
        <style> [x-cloak] { display: none !important; } </style>
        .....
    </head>
    
    <body>
    
    <button @click="toggleMenu"
            @keydown.escape="closeMenu"
    >
        Toggle menu
    </button>
    
    <div x-cloak
         x-show="isMenuOpen"
         @click.away="closeMenu"
         @keydown.escape="closeMenu"
    >
        Menu is open.
    </div>
    
    </body>
    

    Note: if you are using AlpineJs 3 the correct modifier is outside not away (@click.outside)