← Back to all tutorials

How to creat a contextual menu with Tailwind CSS and Alpinejs

Contextual menu with Tailwind CSS and Alpinejs
Published on May 08 2024 by Michael Andreuzza

Let’s hack the right click event and create a contextual menu with Tailwind CSS and Alpinejs. We’ll use the @contextmenu.prevent directive to prevent the browser from opening the default contextual menu.

What is a contextual menu?

A contextual menu is a menu that appears when you right click on an element. It is a popup menu that provides additional options for the user to choose from. Contextual menus are commonly used in web applications to provide users with additional functionality or options when they right-click on a specific element.

Use cases:

  • File management: A contextual menu is used to manage files and folders in a file system.
  • Editing: A contextual menu is used to edit text, images, and other media files.
  • Navigation: A contextual menu is used to navigate between different pages or sections of a website.
  • Tools: A contextual menu is used to access various tools and features that are specific to a particular application or software.

And many more…

This is the structure of the project: Understanding the code:

The wrapper element

  • x-data="{ isOpen: false }": This is the data object that holds the state of the contextual menu.
  • x-data="{ isOpen: false, position: { x: 0, y: 0 }, areaWidth: 0, areaHeight: 0 }": This is the data object that holds the position and dimensions of the contextual menu.
  • areaWidth = $refs.area.offsetWidth; areaHeight = $refs.area.offsetHeight: This is a JavaScript code that sets the areaWidth and areaHeight variables to the width and height of the contextual menu element.

The area element

  • @contextmenu.prevent="isOpen = true; position = contextMenuPosition($event)": This is a directive that prevents the browser from opening the default contextual menu when the right mouse button is clicked.
  • @click.away="isOpen = false": This is a directive that closes the contextual menu when the user clicks outside of it.
  • x-ref="area": This is a directive that references the contextual menu element.

The menu element

  • x-show="isOpen": This is a directive that shows the contextual menu when the isOpen variable is true.
  • x-transition:enter="transition ease-out duration-100": This is a directive that applies a transition effect when the contextual menu is shown.
  • x-transition:enter-start="opacity-0 scale-95": This is a directive that sets the initial state of the contextual menu when it is shown.
  • x-transition:enter-end="opacity-100 scale-100": This is a directive that sets the final state of the contextual menu when it is shown.
  • x-transition:leave="transition ease-in duration-75": This is a directive that applies a transition effect when the contextual menu is hidden.
  • x-transition:leave-start="opacity-100 scale-100": This is a directive that sets the initial state of the contextual menu when it is hidden.
  • x-transition:leave-end="opacity-0 scale-95": This is a directive that sets the final state of the contextual menu when it is hidden.
  • x-style="top: ${Math.min(position.y, areaHeight - $refs.menu.offsetHeight)}px; left: ${Math.min(position.x, areaWidth - $refs.menu.offsetWidth)}px;": This is a directive that sets the position of the contextual menu based on the position of the user’s mouse cursor.
  • @click.away="isOpen = false": This is a directive that closes the contextual menu when the user clicks outside of it.
  • x-ref="menu": This is a directive that references the contextual menu element.

Teh script tag

  • function contextMenuPosition(event) {: This is a function that calculates the position of the contextual menu based on the position of the user’s mouse cursor.
  • return {: This is a function that returns an object with the position of the contextual menu.
  • x: event.clientX,: This is a function that sets the x property of the returned object to the x-coordinate of the user’s mouse cursor.
  • y: event.clientY,: This is a function that sets the y property of the returned object to the y-coordinate of the user’s mouse cursor.

Classes are removed for brevity, but I’ll keep those classes relevant to the tutorial.

<div x-data="{ isOpen: false }">
  <div
    x-data="{ isOpen: false, position: { x: 0, y: 0 }, areaWidth: 0, areaHeight: 0 }"
    x-init="areaWidth = $refs.area.offsetWidth; areaHeight = $refs.area.offsetHeight">
    <div
      @contextmenu.prevent="isOpen = true; position = contextMenuPosition($event)"
      @click.away="isOpen = false"
      x-ref="area">
      Right click here
    </div>
    <div
      x-show="isOpen"
      x-transition:enter="transition ease-out duration-100"
      x-transition:enter-start="opacity-0 scale-95"
      x-transition:enter-end="opacity-100 scale-100"
      x-transition:leave="transition ease-in duration-75"
      x-transition:leave-start="opacity-100 scale-100"
      x-transition:leave-end="opacity-0 scale-95"
      x-style="`top: ${Math.min(position.y, areaHeight - $refs.menu.offsetHeight)}px; left: ${Math.min(position.x, areaWidth - $refs.menu.offsetWidth)}px;`"
      @click.away="isOpen = false"
      x-ref="menu">
      <ul>
        <li>
          <a
            href="#"
            >Menu Item 1</a
          >
        </li>
        <li>
          <a
            href="#"
            >Menu Item 2</a
          >
        </li>

      </ul>
    </div>
    <script>
      function contextMenuPosition(event) {
        return {
          x: event.clientX,
          y: event.clientY,
        };
      }
    </script>
  </div>
</div>

Conclusion

In this tutorial, we learned how to create a contextual menu with Tailwind CSS and Alpinejs. Sais this, is not recommended to use this method for a production website, but it is a good starting point for learning how to create a contextual menu. In fact, do not make contextual menus a part of your website design, as they can be distracting and confusing for users, the web already has a lot of contextual menus, so it is better to use them sparingly and only when necessary and make sure they are easy to use, understand, navigate, , customize and accessible.

Hope you enjoyed this tutorial, have a great day!

/Michael Andreuzza

Did you like this tutorial? Please share it with your friends!

Reviews and opinions

  • "I bought a beautiful theme from Lexington a couple weeks ago. I didn't know Astro at the time, but Michael helped me get set up and really went above and beyond with his support. Now I'm happily redoing my site to look gorgeous with his template."

    Stuart

    Stuart

    Creator of saasydb.com

  • "Michael is one of the best designers on Twitter, would highly recommend his Lexington Themes if you want something in tailwind that doesn’t look the same as everyone else!"

    Alex Hughes

    Alex Hughes

    letsloopin.com

Get lifetime access to every theme available today for $199 and own them forever. Plus, new themes, lifetime updates, use on unlimited projects and enjoy lifetime support.

No subscription required!

Lexington

Beautifully designed HTML, Astro.js and Tailwind themes! Save months of time and build your startup landing page in minutes.