A solid, fully customizable, reactive dropdowns package for Meteor.
Install lookback:dropdowns from Atmosphere:
meteor add lookback:dropdowns{{ ! In a template }}
{{#dropdownTrigger name="uniqueName" }}
<button>Trigger</button>
{{/dropdownTrigger}}
{{#dropdown name="uniqueName"}}
<p>Hello world!</p>
{{/dropdown}}A dropdown consist of a trigger and the actual dropdown content. They are wrapped in Meteor template helpers, in order to create contained components. The templates are:
dropdownTriggerdropdown
Meteor's template helpers can take a bunch of arguments for customization, but the only required one for the dropdowns to work is the name argument, which takes a string which should be unique in order to identify the dropdown.
Simply use the templates dropdownTrigger and dropdown in order to wrap the triggering element and the dropdown:
{{#dropdownTrigger name="dropdownTest" }}
<button>Trigger #1</button>
{{/dropdownTrigger}}
{{#dropdown name="dropdownTest"}}
<p>Hello world</p>
{{/dropdown}}You can also use a separate template for the dropdown and dropdown trigger content:
{{ > dropdownTrigger name="testDropdown2" template="testDropdownTrigger" }}
{{ > dropdown name="testDropdown2" }}
<!-- Somewhere else .. -->
<template name="testDropdownTrigger">
<button>Trigger #2</button>
</template>
<template name="testDropdown2">
<p>External content, yo.</p>
</template>Note that dropdownTrigger needs the template name in the template argument.
The dropdownTrigger accepts these additional arguments:
hideOthers- Defaults totrue. Iffalse, other visible dropdowns won't be hidden when a dropdown is toggled.
The dropdown helper takes additional arguments for positioning and custom classes. The names are:
align- Defaults tocenter. Can also beleftorright.left- Left offset in pixels. Defaults to0.top- Top offset in pixels. Defaults to0.classes- Additional class names for the dropdown. None as default.direction- One ofn,s,eorw. Where to position the dropdown around the element. Defaults tos.persistent- Defaults tofalse. Set totrueif you want the dropdown not to hide when clicking outside it (ondocument).
{{#dropdownTrigger name="testDropdown3"}}
<button>Custom dropdown</button>
{{/dropdownTrigger}}
{{#dropdown name="testDropdown3" align="right" top="20" left="10" direction="n" classes="custom-class another-one"}}
<p>Custom dropdown.</p>
{{/dropdown}}The dropdownTrigger template helper doesn't produce any extra HTML around your content. dropdown on the other hand produces the following HTML:
{{#dropdownTrigger}}
<button>A trigger</button>
{{/dropdownTrigger}}
<!-- Produces: -->
<button class="dropdown__trigger">A trigger</button>
{{#dropdown name="testDropdown4" align="center" top="20" left="10" classes="custom-class"}}
<!-- Content [..] -->
{{/dropdown}}
<!-- Produces: -->
<div role="menu"
class="dropdown test-dropdown4 custom-class"
id="test-dropdown4"
style="position: absolute; left: XXpx; top: XXpx;"
data-dropdown-key="testDropdown4"
data-dropdown-align="center"
data-dropdown-left="10"
data-dropdown-top="20">
<div class="dropdown-arrow"></div>
<!-- Content [..] -->
</div>
As shown, name, align, left and top produces corresponding data-dropdown- attributes in the markup, handy for custom CSS styling. The dropdown's name will be the id attribute and applied as a class.
It is recommended to wrap both the trigger and dropdown markup in a container element with relative positioning.
Please note that the name template argument will be present as id and class in snake-case form.
In order to detect active, opened dropdowns, the global dropdownIsActive helper can be used:
{{#dropdownTrigger name="testDropdown5"}}
<button class="{{#if dropdownIsActive 'testDropdown5'}}dropdown--open{{/if}}">A trigger</button>
{{/dropdownTrigger}}
Both the dropdown and its trigger inherits the data context from its parent:
Template.testTemplate.helpers(
items: ['Foo', 'Bar', 'Baz']
)<template name="testTemplate">
{{#dropdownTrigger name="testDropdown6"}}
<button>Dropdown with data</button>
{{/dropdownTrigger}}
{{#dropdown name="testDropdown6" classes="dropdown--menu" align="left"}}
<ul class="dropdown__menu">
{{#each items}}
<li role="menuItem"><a href="#">{{this}}</a></li>
{{/each}}
</ul>
{{/dropdown}}
</template>One can build more complex components from this simple dropdown concept, such as filterables.
Dropdowns can be persistent too, which means they won't close when you click anywhere outside them. It's done setting persistent to true on a dropdown template:
{{#dropdownTrigger name="persistentDropdown"}}
<button>Persistent dropdown</button>
{{/dropdownTrigger}}
{{#dropdown name="persistentDropdown" persistent="true"}}
<p>
This one is persistent.
</p>
{{/dropdown}}
The dropdown uses the excellent Momentum package for creating natural animations when toggled. This is built on Meteor's UI hooks, since the dropdown content actually is removed from the DOM when hidden.
Two animations are included: spring and appear.
springis making the dropdown appear with a spring physics effect.appearis simply showing and hiding the dropdown as-is.
You can change the default animation for all dropdowns by defining a new Momentum plugin and refer to it by its string name:
Dropdowns.animations.default = 'name-of-momentum-plugin';You can also change animation per dropdown basis. Just specify the animation attribute for the dropdown helper.
<div class="test-area dropdown-container">
{{#dropdownTrigger name="appearAnimation"}}
<button>Non-standard animation</button>
{{/dropdownTrigger}}
{{#dropdown name="appearAnimation" animation="appear"}}
<p>Hey there.</p>
{{/dropdown}}
</div>No CSS styling is provided with this dropdown package – it's up to you to style the dropdown according to your needs. For a complete styling example, check out the _dropdowns.scss file in this repository.
This package exports a namespaced object: Dropdowns. By the power of reactivity, all dropdowns are based on an underlying data structure which stores its (quite minimal) state. When that data changes, for instance if the position is changed over an API call, the UI will react. The Dropdowns object has the following methods:
# This is the struct for a "dropdown" object, returned
# by Dropdowns.get('key')
{
name: 'key'
showing: false
align: 'center'
x: 0
y: 0
top: 10
left: 0
persistent: false
element: -> # jQuery reference to the dropdown component in the DOM.
}
# Manually create a dropdown with a name.
Dropdowns.create('name', opts = {top: 10, left: 0, align: 'center'})
# Get a the dropdown.
Dropdowns.get('name')
# Hide a dropdown.
Dropdowns.hide('name')
# Show a dropdown.
Dropdowns.show('name')
# Returns `true` if a dropdown is currently shown.
Dropdowns.isShown('name')
# Toggle a dropdown.
Dropdowns.toggle('name')
# Hide all dropdowns.
Dropdowns.hideAll()
# Destroy a dropdown.
Dropdowns.remove()
# Destroy all dropdowns.
Dropdowns.removeAll()
# Manually set a position of a dropdown. Both x and y are optional.
Dropdowns.setPosition('name', {x: Number, y: Number})
# Hide all dropdowns except for `name` (can also be an array of names).
Dropdowns.hideAllBut('name')
# Get names of all persistent dropdowns
Dropdowns.getPersistentKeys()
# Returns a dict of all dropdowns
Dropdowns.all()
# Position dropdown <name> around a DOM element <reference>
Dropdowns.positionDropdown('name', document.getElementById('reference'))1.5.1- Usekeyupevent for closing all dropdowns.1.5.0- IntroducehideOtherstemplate option on a dropdown.1.4.2- ExposeDropdowns.positionDropdown().1.4.1- ExposeDropdowns.all().1.4.0- Use
data-dropdown-keyattribute when positioning dropdowns, instead ofid. - Expose dropdown name on the
nameproperty of a dropdown object. - Add
element()function on dropdown objects returned fromDropdowns.get().element()returns a jQuery reference to the DOM element for the dropdown.
- Use
1.3.0- Add support for custom animations.1.2.1- Addpersistentoption.1.2.0- Add support for dropdown directions. Note that this release removes the default top offset (10px).1.0.0- Stable release.0.4.1- Fix: The properties
x, y, top, leftare now flattened (before, they were in propertiespositionandoffsetrespectively). - Fix: Said properties are converted to
Numberswhen creating aDropdown.
- Fix: The properties
0.4.0Rewrite logic to be based on data reactivity instead of DOM state.- New: New API methods on the
Dropdownsglobal. - New: New template helper for the dropdown trigger (
dropdownTrigger).
- New: New API methods on the
0.3.3Fix: Issue where a descendant element of a trigger would cause dropdown to hide.0.3.2New: Add.dropdown__arrowdiv to template.0.3.1Fix: Support snake-case for classes and ids in dropdown template.0.3.0Move foundational dropdown wrapper markup into the template.0.2.0New: Support for horizontal positioning.0.1.0Initial commit.
This package's API interface (methods on the Dropdown object) is unit tested. Those tests reside in /tests.
npm testContributions are welcome. Please open issues and/or file Pull Requests.
Made by Lookback.