DropLab

A generic dropdown for all of your custom dropdown needs.

Usage

DropLab can be used by simply adding a data-dropdown-trigger HTML attribute. This attribute allows us to find the "trigger" (toggle) for the dropdown, whether that is a button, link or input.

The value of the data-dropdown-trigger should be a CSS selector that DropLab can use to find the trigger's dropdown list.

You should also add the data-dropdown attribute to declare the dropdown list. The value is irrelevant.

The DropLab class has no side effects, so you must always call .init when the DOM is ready. DropLab.prototype.init takes the same arguments as DropLab.prototype.addHook. If you do not provide any arguments, it will globally query and instantiate all droplab compatible dropdowns.

<a href="#" data-dropdown-trigger="#list">Toggle</a>

<ul id="list" data-dropdown>
  <!-- ... -->
<ul>
const droplab = new DropLab();
droplab.init();

As you can see, we have a "Toggle" link, that is declared as a trigger. It provides a selector to find the dropdown list it should control.

Static data

You can add static list items.

<a href="#" data-dropdown-trigger="#list">Toggle</a>

<ul id="list" data-dropdown>
  <li>Static value 1</li>
  <li>Static value 2</li>
<ul>
const droplab = new DropLab();
droplab.init();

Explicit instantiation

You can pass the trigger and list elements as constructor arguments to return a non-global instance of DropLab using the DropLab.prototype.init method.

<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>

<ul id="list" data-dropdown>
  <!-- ... -->
<ul>
const trigger = document.getElementById('trigger');
const list = document.getElementById('list');

const droplab = new DropLab();
droplab.init(trigger, list);

You can also add hooks to an existing DropLab instance using DropLab.prototype.addHook.

<a href="#" data-dropdown-trigger="#auto-dropdown">Toggle</a>
<ul id="auto-dropdown" data-dropdown><!-- ... --><ul>

<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
<ul id="list" data-dropdown><!-- ... --><ul>
const droplab = new DropLab();

droplab.init();

const trigger = document.getElementById('trigger');
const list = document.getElementById('list');

droplab.addHook(trigger, list);

Dynamic data

Adding data-dynamic to your dropdown element will enable dynamic list rendering.

You can template a list item using the keys of the data object provided. Use the handlebars syntax {{ value }} to HTML escape the value. Use the <%= value %> syntax to simply interpolate the value. Use the <%= value %> syntax to evaluate the value.

Passing an array of objects to DropLab.prototype.addData will render that data for all data-dynamic dropdown lists tracked by that DropLab instance.

<a href="#" data-dropdown-trigger="#list">Toggle</a>

<ul id="list" data-dropdown data-dynamic>
  <li><a href="#" data-id="{{id}}">{{text}}</a></li>
</ul>
const droplab = new DropLab();

droplab.init().addData([{
  id: 0,
  text: 'Jacob',
}, {
  id: 1,
  text: 'Jeff',
}]);

Alternatively, you can specify a specific dropdown to add this data to but passing the data as the second argument and and the id of the trigger element as the first argument.

<a href="#" data-dropdown-trigger="#list" id="trigger">Toggle</a>

<ul id="list" data-dropdown data-dynamic>
  <li><a href="#" data-id="{{id}}">{{text}}</a></li>
</ul>
const droplab = new DropLab();

droplab.init().addData('trigger', [{
  id: 0,
  text: 'Jacob',
}, {
  id: 1,
  text: 'Jeff',
}]);

This allows you to mix static and dynamic content with ease, even with one trigger.

Note the use of scoping regarding the data-dropdown attribute to capture both dropdown lists, one of which is dynamic.

<input id="trigger" data-dropdown-trigger="#list">
<div id="list" data-dropdown>
  <ul>
    <li><a href="#">Static item 1</a></li>
    <li><a href="#">Static item 2</a></li>
  </ul>
  <ul data-dynamic>
    <li><a href="#" data-id="{{id}}">{{text}}</a></li>
  </ul>
</div>
const droplab = new DropLab();

droplab.init().addData('trigger', [{
  id: 0,
  text: 'Jacob',
}, {
  id: 1,
  text: 'Jeff',
}]);

Internal selectors

DropLab adds some CSS classes to help lower the barrier to integration.

For example,

  • The droplab-item-selected css class is added to items that have been selected either by a mouse click or by enter key selection.
  • The droplab-item-active css class is added to items that have been selected using arrow key navigation.
  • You can add the droplab-item-ignore css class to any item that you do not want to be selectable. For example, an <li class="divider"></li> list divider element that should not be interactive.

Internal events

DropLab uses some custom events to help lower the barrier to integration.

For example,

  • The click.dl event is fired when an li list item has been clicked. It is also fired when a list item has been selected with the keyboard. It is also fired when a HookButton button is clicked (a registered button tag or a tag trigger).
  • The input.dl event is fired when a HookInput (a registered input tag trigger) triggers an input event.
  • The mousedown.dl event is fired when a HookInput triggers a mousedown event.
  • The keyup.dl event is fired when a HookInput triggers a keyup event.
  • The keydown.dl event is fired when a HookInput triggers a keydown event.

These custom events add a detail object to the vanilla Event object that provides some potentially useful data.

Plugins

Plugins are objects that are registered to be executed when a hook is added (when a droplab trigger and dropdown are instantiated).

If no modules API is detected, the library will fall back as it does with window.DropLab and will add window.DropLab.plugins.PluginName.

Usage

To use plugins, you can pass them in an array as the third argument of DropLab.prototype.init or DropLab.prototype.addHook. Some plugins require configuration values, the config object can be passed as the fourth argument.

<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
<ul id="list" data-dropdown><!-- ... --><ul>
const droplab = new DropLab();

const trigger = document.getElementById('trigger');
const list = document.getElementById('list');

droplab.init(trigger, list, [droplabAjax], {
  droplabAjax: {
    endpoint: '/some-endpoint',
    method: 'setData',
  },
});

Documentation

Development

When plugins are initialised for a droplab trigger+dropdown, DropLab will call the plugins init function, so this must be implemented in the plugin.

class MyPlugin {
  static init() {
    this.someProp = 'someProp';
    this.someMethod();
  }

  static someMethod() {
    this.otherProp = 'otherProp';
  }
}

export default MyPlugin;