excid3 / tailwindcss-stimulus-components

A set of StimulusJS components for TailwindCSS apps similar to Bootstrap JS components.

Home Page:https://excid3.github.io/tailwindcss-stimulus-components/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dropdown improvements

adrienpoly opened this issue · comments

Hello

I am contemplating bringing a few improvements to the dropdown component. Before doing so I wanted to confirm the appetite for those changes.

Simplify the API

Currently, the recommended markup is:

<div data-controller="dropdown" data-action="click->dropdown#toggle click@window->dropdown#hide">
  <div id="dropdown-button" class="relative inline-block">
    <div role="button" tabindex="0" data-dropdown-target="button" class="inline-block select-none">
      <span class="appearance-none flex items-center inline-block">
        <span>Dropdown Example</span>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="fill-current h-4 w-4"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"></path></svg>
      </span>
    </div>
    <div data-dropdown-target="menu"
          data-transition-enter="transition ease-out duration-200"
          data-transition-enter-from="opacity-0 translate-y-1"
          data-transition-enter-to="opacity-100 translate-y-0"
          data-transition-leave="transition ease-in duration-150"
          data-transition-leave-from="opacity-100 translate-y-0"
          data-transition-leave-to="opacity-0 translate-y-1"
          class="hidden absolute top-4 right-0 z-10 mt-5 flex w-screen max-w-max">
      <div class="text-sm bg-white shadow-lg rounded border overflow-hidden w-32">
        <a data-dropdown-target="menuItem" data-action="keydown.up->dropdown#previousItem:prevent keydown.down->dropdown#nextItem:prevent" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Account</a>
        <a data-dropdown-target="menuItem" data-action="keydown.up->dropdown#previousItem:prevent keydown.down->dropdown#nextItem:prevent" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Billing</a>
        <hr class="border-t" />
        <a data-dropdown-target="menuItem" data-action="keydown.up->dropdown#previousItem:prevent keydown.down->dropdown#nextItem:prevent" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Sign Out</a>
      </div>
    </div>
  </div>

I see several improvements opportunities

  1. keydown.up and keydown.down are being defined at each menuitem. I think it is a bit overkill and we should be able to have a single .up/.down listener higher up in the markup. Or even better those actions should be self defined by the controller so the user doesn't have to worry about them
  2. "data-action="click->dropdown#toggle click@window->dropdown#hide". I think we always want to have those actions so they could be self defined by the controller too.
  3. Transition : this adds a lot to the html boilerplate: suggestion add default values (the one from the example) so that we can ommit this part
  4. aria : add some basic support for the aria attributes (not an expert but the basics should be quit easy)

the target mark up would be something like that (+aria):

<div data-controller="dropdown">
  <div id="dropdown-button" class="relative inline-block">
    <div role="button" tabindex="0" data-dropdown-target="button" class="inline-block select-none">
      <span class="appearance-none flex items-center inline-block">
        <span>Dropdown Example</span>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="fill-current h-4 w-4"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"></path></svg>
      </span>
    </div>
    <div data-dropdown-target="menu" class="hidden absolute top-4 right-0 z-10 mt-5 flex w-screen max-w-max">
      <div class="text-sm bg-white shadow-lg rounded border overflow-hidden w-32">
        <a data-dropdown-target="menuItem" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Account</a>
        <a data-dropdown-target="menuItem" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Billing</a>
        <hr class="border-t" />
        <a data-dropdown-target="menuItem" href="#" class='no-underline block pl-4 py-2 text-gray-900 bg-white hover:bg-gray-100 whitespace-no-wrap focus:bg-gray-100'>Sign Out</a>
      </div>
    </div>
  </div>
</div>

Keeping the same functionalities but with simpler markup

1 & 2 - I agree, it feels like a pain point to have to define those regularly.
3. I agree. Defaults would simplify a lot and having an easy way to override them. I was talking to @marcoroth about having default class values as a feature in Stimulus to help with this but I got lost in the TypeScript and never finished it.
4. Yes! The accessibility stuff is needed.
5. One other thing I'd like to figure out is how can we launch modals from dropdown items.

Happy to help with 3 and to get that into Stimulus proper 🙌🏼

Ok so it seems appetite is here 🍽️

will try to work on 1, 2 & 4 first

For 3

Currently it is defined like that

const transitionClasses = element.dataset.transitionEnter || "enter"
const fromClasses = element.dataset.transitionEnterFrom || "enter-from"
const toClasses = element.dataset.transitionEnterTo || "enter-to"
const toggleClass = element.dataset.toggleClass || "hidden"

We don't use at all the Stimulus Class API actually.

My idea was to add the possibility of passing transition options from the Stimulus controller to the Transition function

- export async function enter(element) {
- const transitionClasses = element.dataset.transitionEnter || "enter"
+ export async function enter(element, transitions = {}) {
+ const transitionClasses = transitions.enter || element.dataset.transitionEnter || "enter"

and in the stimulus controller, we could have once available the Class API with default value. In the meantime we can have dedicated getters

But it will be a breaking change in case someone defined the "enter" class