Here's Flux's kick-ass dropdown menu for free

Heyyyy folks,

I said I would hit you up in a few days with something free and cool. Well... here we go.

Dropdown menus are one of the hardest things to build in web development. Don't believe me? Lemme show you.

Ok, so you need a dropdown in your app. Maybe you're using Vue, React, Alpine, whatever. Your first crack looks something like this:

What you see here is not a dropdown menu. It's a...menu that drops down? But it's missing some essential pieces. Let me explain those pieces in the form of a condescending line of questioning:

  • Does it close when you click elsewhere on the page?
  • Does it close when you press Escape?
  • When you close it, does it move browser focus back to the trigger button?
  • If it's contained inside a div with `overflow: hidden; position: relative`, will it still be visible outside the overflow boundaries?
  • If the trigger is near the bottom of the page, will the dropdown pop "up" instead of down to avoid getting cut-off?
  • Will a screen reader or other assistive technologies know that this is a dropdown? (Aka did you add the necessary aria attributes?)

No? I get it. I literally wrote an entire JavaScript framework to make building dropdowns easy (AlpineJS), only to find out the dropdowns myself and others were building weren't actually proper dropdowns. 🤦‍♂️

So. When I started building Flux, I knew I had to do better. I knew Flux needed a first-class dropdown with all the woozles and doodles necessary for professional web apps.

This is what the most basic dropdown looks like in Flux:

How simple is that? Flux uses the browser's new "popover" attribute combined with some custom JavaScript to make a much more robust dropdown that's even simpler to write.

Just pass a button and a popover element into <flux:dropdown> and you get all the aforementioned features: keyboard stuff, accessibility stuff, overflow stuff, positioning stuff, etc.

Ok, so this is cool, but what about "system menus"? Or rather dropdown menus that behave more like a menu in your operating system. These are often called "action menus".

Let's play the same game as before, except this time, with an "action" menu. Here's the most basic menu in Alpine:

Notice, the only real difference this time around is we're using buttons instead of links. The intention of this menu is to provide "actions" instead of "navigation".

Welp, turns out there's a whole new set of rules to abide by for "action menus" (in ADDITION to all the other rules):

  • Can you open this menu by pressing the down arrow key?
  • Can you use the arrow keys to navigate up and down the menu?
  • Can you type the first letter of a menu item to highlight it?
  • Will arrow key navigation skip disabled buttons?
  • Will you ensure only one action is focusable at any given time?
  • Do screen readers know this is an "action menu"? (Has role="menu" attribute)

Of course, given the simple screenshot above, the answer is a resounding NO to all of these questions.

So what does a complete action menu look like in Flux? Check it out:

Ok, now we're cookin'. What about that keyboard navigation?

While we're showing off, let's keep going. Here's how the Flux dropdown menu behaves when it gets cut-off by the bottom of the page:

You can also customize the positioning of the menu with the position="?" property:

We've only scratched the surface.

What about menu item icons, keyboard hints, separators, groups, labels, checkboxes, radio buttons? We've got em. Check it out:

That's all well and good, but it's still playing on "easy" mode. If you want to climb dropdown mountain, you'll need to beat the final boss at the top: SUBMENUS

Deciding to tackle submenus changed the entire trajectory of this project. It marked a definitive point where I decided to go all in and make a world-class tool that would stand out even amongst component libraries in other ecosystems. Check it out:

Submenus may seem harmless, but I assure you they are not. You have to handle all these extra focus and keyboard and mouse and positioning scenarios you didn't have to before.

Especially if you want to support infinite nesting.

And all of this is child's play in comparison to the cherry on top: Submenu safe areas.

What are safe areas? They are invisible overlays between your cursor and a submenu allowing you to travel to submenus diagonally without closing the menu accidentally.

Let me demonstrate by highlighting the safe area with CSS:

Pretty next level right?

"This is sick, but this must be an absolute monstrosity of a Blade component under the hood..."

Nope, this is literally the contents of the `<flux:menu>` Blade component:

I extracted all the tricky UI bits of Flux into custom web elements so that they are easy to style and maintain from Blade. Nothing about this dropdown is big, slow, or clunky. It's all lightweight and breezy fast. (I think I just invented the phrase "breezy fast")

This also means I can ship bugfixes without you needing to modify your Blade files.

I feel like I created an entirely separate JavaScript framework just for Flux. I'm nearly as excited about what's under the hood as I am about what's over it.

If you're impressed by the level of care that went into this component, just imagine what went into the modal, tooltips, tabs, custom selects, comboboxes, autocompletes, radio/checkbox groups, toasts, etc. A LOT lol.

So yeah. I'm making the whole dropdown component and the entire icon set free and open source today.

Go to https://github.com/livewire/flux for installation instructions and start pulling this into your apps.

If you like what you see? Hang tight till Sept 23rd when I launch the entire project officially.

All your kindness and support means the world to me. Truly.

Thanks for being a part of this wild ride, and let's make Livewire + Flux the most dangerous combo in all of web development.

-Caleb

Comments

Popular posts from this blog

🥳 Flux UI is now live!

C# lists, Regression Testing, and much more!

New Livewire Data Tables series is here!