Jolty UI Jolty UI Documentation Icons Colors

Dropdown

Compact UI element with links and keyboard navigation. Ideal for menus, selection lists, and action items.

Getting started

First, create two elements: <button> and <div> with menu items, and assign a unique id to it.

html
<button data-ui-toggle="my-dropdown">Account</button>
<div class="ui-dropdown" data-ui-dropdown id="my-dropdown" hidden>
  <a href="#" class="ui-dropdown-item" data-ui-dropdown-item>History</a>
  <a href="#" class="ui-dropdown-item" data-ui-dropdown-item>Settings</a>
  <button type="button" class="ui-dropdown-item" data-ui-dropdown-item>Sign Out</button>
</div>

Placement

By default, the dropdown will be placed below the trigger element. You can change this behavior by adding the data-ui-placement attribute to the dropdown element.

html
<button data-ui-toggle="my-dropdown" class="my-dropdown-btn">Account</button>
<div class="ui-dropdown" data-ui-dropdown data-ui-placement="top">...</div>

You can also use CSS variables to set the position by assigning them to the .dropdown element.

css
.dropdown {
  --ui-dropdown-placement: top;
}

Or set the position for the button that triggers the dropdown; this is convenient when the dropdown body is located in a different element, for example in the <body>.

css
.my-dropdown-btn {
  --ui-dropdown-placement: top;
}

Trigger

Now, let’s provide the ability to open the dropdown through 'hover' by adding the attribute data-ui-trigger.

html
<button data-ui-toggle="my-dropdown">Account</button>
<div data-ui-dropdown data-ui-trigger="click hover" id="my-dropdown" hidden>...</div>

For 'hover', it has a delay of 200ms to prevent unintentional opening and closing of the dropdown. However, this can be modified using the delay.

Events

Let’s create a dropdown that, when clicking on a button with data-action="delete" attribute, will display a message asking for confirmation.

You can read more about events in the Events section.

html
<button data-ui-toggle="my-dropdown">Action</button>
<div data-ui-dropdown id="my-dropdown" hidden>
  <button type="button" data-ui-dropdown-item data-action="view">View</button>
  <button type="button" data-ui-dropdown-item data-action="edit">Edit</button>
  <button type="button" data-ui-dropdown-item data-action="delete">Delete</button>
</div>
js
Dropdown.get("my-dropdown")?.on("hide", dropdown, { trigger }) => {
  if (trigger?.dataset?.action === "delete") {
    confirm(`Are you sure you want to delete it?`);
  }
});

Settings groups

However, what if you have multiple dropdowns and you don’t want to bind each one with a unique id, but instead wish to set common settings? There’s a static method for that, Dropdown.data().

You can remove all previously added data-attributes, keeping only the data-ui-dropdown and data-action attribute for our example.

html
<button data-ui-toggle="my-dropdown">Action <span></span></button>
<div data-ui-dropdown="my-dropdown" id="my-dropdown" hidden>
  <button type="button" data-ui-dropdown-item data-action="view">View</button>
  <button type="button" data-ui-dropdown-item data-action="edit">Edit</button>
  <button type="button" data-ui-dropdown-item data-action="delete">Delete</button>
</div>
js
Dropdown.data("action", (dropdownElem) => {
  return {
    toggler: dropdownElem.previousElementSibling,
    items: "[data-action]",
    async itemClickHide(dropdown, { trigger }) {
      if (trigger.dataset.action === "delete") {
        if (!confirm(`Are you sure you want to delete it?`)) return;
        // await something();
        dropdown.hide();
        return false;
      }
      return true;
    },
  };
});
Dropdown.initAll();

Styles

css
.dropdown {
  --ui-dropdown-color: var(--ui-panel-color);
  --ui-dropdown-bg: var(--ui-panel-bg);
  --ui-dropdown-border-style: var(--ui-panel-border-style);
  --ui-dropdown-border-width: var(--ui-panel-border-width);
  --ui-dropdown-border-color: var(--ui-panel-border-color);
  --ui-dropdown-outline: var(--ui-panel-outline);
  --ui-dropdown-outline-offset: var(--ui-panel-outline-offset);
  --ui-dropdown-shadow: var(--shadow-lg);
  --ui-dropdown-border-radius: var(--radius);
  --ui-dropdown-flip: 1;
  --ui-dropdown-sticky: 1;
  --ui-dropdown-shrink: 1;
  --ui-dropdown-offset: 0.75rem;
  --ui-dropdown-arrow-width: 0.75rem;
  --ui-dropdown-arrow-height: 0.75rem;
  --ui-dropdown-boundary-offset-top: var(--ui-boundary-offset-top);
  --ui-dropdown-boundary-offset-end: var(--ui-boundary-offset-end);
  --ui-dropdown-boundary-offset-bottom: var(--ui-boundary-offset-bottom);
  --ui-dropdown-boundary-offset-start: var(--ui-boundary-offset-start);
  --ui-dropdown-padding: 0.325rem;
  --ui-dropdown-transition-duration: var(--duration-2);
  --ui-dropdown-item-padding: 0.25rem 0.75rem;
  --ui-dropdown-item-border-radius: var(--radius-sm);
  --ui-dropdown-item-hover-bg: var(--gray-a2);
  --ui-dropdown-item-outline-color: var(--gray-9);
  &::backdrop {
    --ui-dropdown-backdrop-bg: var(--ui-backdrop-bg);
    --ui-dropdown-backdrop-light-bg: var(--ui-backdrop-light-bg);
    --ui-dropdown-backdrop-transition: opacity var(--ui-dropdown-transition-duration) var(--ease-3);
  }
}

Options

NameTypeDefaultDescription
initBooleantrueShould the instance be automatically initialized when an instance is created? If false, you’ll need to manually initiate it by calling dropdown.init().
destroyBooleanfalseAllows you to destroy an instance at a specific breakpoint.
dataString''Allows you to use the default options that have been added by the Dropdown.data() static method.
onObjectnullUsed to register event handlers.
appearBooleannullIf you want to apply a transition upon initialization as well, you can set this option to true. Attribute: data-ui-appear
eventPrefixString'ui-dropdown:'Prefix for events dispatched on the dropdown element.
eventDispatchBooleantrueDefines if events are dispatched or used only within options.
eventBubbleBooleantrueDefines if events should bubble up the DOM.
breakpointsObjectnullDefines custom options for specific breakpoints.
shownBooleannullDefines if the dropdown is expanded after initialization. By default, it’s null, which means it checks the hidden attribute or another attribute, depending on stateMode.
awaitAnimationBooleanfalseDetermines whether to wait for the end of the animation to trigger 'shown','hidden' events and return a promise.
backDismissBooleantrueDefines whether the element should close when the Esc key is pressed. Attribute: data-ui-back-dismiss
lightDismissBoolean, ObjecttrueDefines whether the element should close when the user clicks outside of it. You can also pass an object with the option {contextMenuClick: false}, which will disable closing the dropdown when the right mouse button is clicked outside of it. Attribute: data-ui-light-dismiss
togglerClassActiveString'ui-active'CSS class for toggler when dropdown is open.
dropdownClassActiveString'ui-active'CSS class for dropdown when it’s open.
triggerString'click'Dropdown supports triggers by 'click' and 'hover'. You may pass multiple triggers; separate them with a space. Attribute: data-ui-trigger
modalBooleanfalseIf the <dialog> tag is used, then it opens in modal mode. Also, the properties focusTrap, backDismiss, lightDismiss, preventScroll, set to 'auto' are triggered Attribute: data-ui-modal
returnFocusBooleantrueDefines whether focus should return to the element that triggered it. You can also pass an object with the option {await: true}, which indicates that it should wait for the end of the transition to return focus.
focusTrapBooleanfalseDefines whether the focus must be trapped inside the dropdown.
preventScrollBooleanfalseDefines whether the CSS class .ui-prevent-scroll should be added to the <html> element when the dropdown is opened.
Use thee --ui-root-scrollbar-width CSS variable to prevent content shifts when the scrollbar disappears with overflow: hidden. Attribute: data-ui-prevent-scroll
dismissBoolean, CSSSelectortrueAllows the dropdown to be hide when clicked on the button. By default, it’s true, meaning the hide() method will be called when '[data-ui-dismiss=""],[data-ui-dismiss="ui-dropdown"]' is clicked.
autofocusBoolean, CSSSelector, ElementtrueDefines the element that should be focused when the dropdown is opened. By default it’s true, meaning the '[autofocus],[data-ui-autofocus]' element will be focused.
itemsCSSSelector, Element[], Function'[data-ui-dropdown-item]'Defines the elements that can be focused by keyboard arrows.
arrowActivationString'y'Determines which arrow keys should open the dropdown when pressed. Supports the values 'x','y','left','right','up','down'.
itemClickHideBoolean, Function, CSSSelector, Element, Element[]trueDefines whether the dropdown should be closed when an item is clicked. Also accepts a function that returns a boolean value (instance, {trigger, event}) => Boolean.
topLayerBooleantrueDetermines whether the dropdown should be displayed in the top layer. CSS Variable: --ui-dropdown-top-layer: 1;
rootElement'body'The element to which the dropdown will be appended.
moveToRootBooleanfalseMoves the dropdown to the element defined in the root option when opened. CSS Variable: --ui-dropdown-move-to-root: 0;
a11yBooleantrueAdds aria-controls, aria-expanded and role="button" attributes to the toggler element.
stateModeString'hidden'Accepts one of the next values 'hidden','hidden-until-found','inert','class-hidden','class-shown','remove' Attribute: data-ui-hide-mode
keepPlaceBooleantrueDefines if the component’s space is preserved when removed by stateMode: 'remove'.

Hide mode

For more details on how to use, read the State mode section.

Transition

For more details on how to use, read the Transition section.

Floating

NameTypeDefaultDescription
placementString'bottom'How to position the dropdown: Use 'top','bottom','left', or 'right'. You can also append '-start' or '-end' to these positions for better alignment of the dropdown, such as 'top-start'.
You can also use the 'dialog' value, in which case the dropdown will be displayed as a dialog, without being attached to the toggler. Attribute: data-ui-placement CSS Variable: --ui-dropdown-placement: bottom;
delayNumber[150, 0]Sets delay when trigger:'hover'. Accepts 2 values, for mouseevent and mouseleave, if one value is set, it applies to both.
offsetNumber0Specifies the offset between the dropdown and the toggler. CSS Variable: --ui-dropdown-offset: 0px;
paddingNumber, Number0Specifies padding from the anchor’s borders. It accepts two values: padding from the start and from the end. If a single value is given, it will be applied to both sides. CSS Variable: --ui-dropdown-padding: 0px;
flipBoolean, Booleantruewhether the dropdown should flip to the opposite placement when there’s not enough space. It can accept two values, corresponding to the X and Y axes. CSS Variable: --ui-dropdown-flip: 1;
stickyBooleantrueDefines whether the dropdown should shift to stay in view during a scroll. CSS Variable: --ui-dropdown-sticky: 1;
shrinkBooleanfalseDefines whether the dropdown should decrease in size to fit when there’s insufficient space. Remember that you must use the generated CSS variables to apply the available sizes. CSS Variable: --ui-dropdown-shrink: 0;
boundaryOffsetNumber, Number[], Object0Specifies padding from the relative parent’s borders. It can accept up to four values like inset or margin CSS properties. You can also specify an object (for JS only) in the form {top: 0, right: 0, bottom: 0, left: 0} CSS Variable: --ui-dropdown-boundary-offset: 0px;

Arrow

NameTypeDefaultDescription
arrowBoolean, ObjecttrueObject with arrow options or false to disable.
widthNumber0Sets the width of the arrow. By default, it gets the width of the data-ui-dropdown-arrow element. CSS Variable: --ui-dropdown-arrow-width: 0px;
heightNumber0Sets the height of the arrow. By default, it gets the height of the data-ui-dropdown-arrow element. CSS Variable: --ui-dropdown-arrow-height: 0px;
offsetNumber0Sets the arrow’s offset from the dropdown. CSS Variable: --ui-dropdown-arrow-offset: 0px;
paddingNumber0Sets padding from the dropdowns’s borders. It accepts two values: padding from the start and from the end. If a single value is given, it will be applied to both sides. CSS Variable: --ui-dropdown-arrow-padding: 0px;

CSS Variables

NameTypeDescription
--ui-floating-widthNumberThe width of the dropdown.
--ui-floating-heightNumberThe height of the dropdown.
--ui-floating-anchor-widthNumberThe width of the toggler.
--ui-floating-anchor-heightNumberThe height of the toggler.
--ui-floating-available-widthNumberThe remaining width between the toggler and the boundary edge.
Only when the shrink option is enabled.
--ui-floating-available-heightNumberThe remaining height between the toggler and the boundary edge.
Only when the shrink option is enabled.
--ui-floating-arrow-leftNumberThe left offset for the arrow.
--ui-floating-arrow-topNumberThe top offset for the arrow.
--ui-floating-transform-originNumberThe transform-origin computed from the content and arrow position

Methods

NameReturnDescription
init()instanceInitializes the component.
destroy(destroyOptions)instance, nullDestroys the component and accepts an object as a option { remove: false, keepInstance: false, keepState: false }.
update(options)instanceAccepts options as an argument and updates the component.
toggle(toggleOptions, force)promiseToggles the component’s visibility state between shown and hidden. Accepts true or false as a option, which sets the animated option or an object { animated: true, silent: false }.
show(toggleOptions)promiseOpens the component and accepts the same options as the toggle() method.
hide(toggleOptions)promiseCloses the component and accepts the same options as the toggle() method.

Class Methods

NameReturnDescription
toggle(id, force, toggleOptions)promiseSearches for an instance by id and calls its toggle() method with the specified options.
show(id, toggleOptions)promiseSearches for an instance by id and calls its show() method with the specified options.
hide(id, toggleOptions)promiseSearches for an instance by id and calls its hide() method with the specified options.
data(name?, data)ClassSets default options for components that have the property data:'name' or by the attribute data-ui-dropdown="name".
updateDefault(options)optionsUpdates default options.
initAll(root)instanceSearches for elements in root, which defaults to document with the attribute data-ui-dropdown and initializes them.
get(id or elem)instanceSearches for an instance by id or element (checks the base property).
getOrCreate(id or elem, options)instanceSearches for an instance by id or element (checks the base property), if not found, creates a new instance with specified options.

Properties

NameTypeDescription
idStringThe id of the base / dropdown element.
isInitBooleanIndicates whether the instance is already initialized.
optsObjectContains the currently applied options for the current breakpoint.
baseOptsObjectContains all options, including the breakpoints option.
base, dropdownElementAll components have a base property, which refers to the element through which the component is initialized and where events are fired. dropdown is the same as base.
isOpenBooleanIndicates whether the dropdown is currently shown.
initialPlaceNodeNodeReference to the node that is located where the dropdown was at the moment of initialization.

Class properties

NameTypeDescription
DefaultObjectContains the default options for all instances.
instancesMapA Map that contains all instances of the Dropdown class.

Events

NameArgumentsDescription
beforeInitinstanceEvent will fired right before initialization.
initinstanceFires when initialization has been completed.
beforeShowinstance, {trigger, event}Fires immediately when the show() method is called.
showinstance, {trigger, event}Fires when the element becomes visible, but the CSS transition hasn’t started yet.
showninstance, {trigger, event}Fires when the CSS transition hasn’t been completed.
beforeHideinstance, {trigger, event}Fires immediately when the hide() method is called.
hideinstance, {trigger, event}Fires just before the CSS transition starts.
hiddeninstance, {trigger, event}Fires when the CSS transition has been completed.
beforeDestroyinstanceFires before the instance is destroyed.
destroyinstanceFires immediately when the destroy() method is called.
breakpointinstance, breakpoint, prevBreakpointFires when the breakpoint has been changed.
anyeventName, instanceFires on any event occurrence. The first argument contains the name of the event.
2024 © A Project by Anatolii Moldovanov