Dropdown Component
Dropdown Component: The Dropdown component creates toggleable dropdown menus that can be used for navigation, select boxes, context menus, and more. It supports various positions, animations, and can contain any type of content including forms, lists, and media.
Live Examples
1. Basic Dropdowns
Example Preview
Dropdown Title
This dropdown appears on click and can contain any content.
2. Navigation Dropdowns
Example Preview
3. Form Select Dropdowns
Example Preview
4. Advanced Dropdown Features
Example Preview
Interactive Content
This dropdown contains interactive elements that remain functional.
Controlled by JavaScript
5. Multi-level Dropdowns
Dropdown Classes & Attributes Reference
Core Attributes
| Attribute | Description | Values | Usage |
|---|---|---|---|
uk-dropdown | Initializes dropdown component | Options object or empty | uk-dropdown="pos: bottom-left" |
uk-navbar | Initializes navbar component | - | uk-navbar |
pos | Dropdown position relative to trigger | bottom-left, bottom-center, bottom-right, top-left, top-center, top-right, left-center, right-center | uk-dropdown="pos: bottom-center" |
mode | Trigger mode | hover, click | uk-dropdown="mode: click" |
delay-show | Delay before showing (ms) | Number | delay-show: 500 |
delay-hide | Delay before hiding (ms) | Number | delay-hide: 200 |
offset | Offset from trigger (px) | Number | offset: 10 |
animation | Animation type | uk-animation-fade, uk-animation-scale-up, etc. | animation: uk-animation-scale-up |
duration | Animation duration (ms) | Number | duration: 300 |
boundary | Boundary element selector | CSS selector | boundary: .container |
boundary-align | Align dropdown within boundary | true, false | boundary-align: true |
stretch | Stretch dropdown to match width | x, y | stretch: x |
Dropdown Classes
| Class | Description | Usage |
|---|---|---|
.uk-dropdown | Base dropdown container | <div class="uk-dropdown"> |
.uk-navbar-dropdown | Navbar dropdown container | <div class="uk-navbar-dropdown"> |
.uk-dropdown-nav | Dropdown navigation list | <ul class="uk-nav uk-dropdown-nav"> |
.uk-navbar-dropdown-nav | Navbar dropdown navigation list | <ul class="uk-nav uk-navbar-dropdown-nav"> |
.uk-navbar-dropdown-width-2 | 2-column navbar dropdown | uk-navbar-dropdown uk-navbar-dropdown-width-2 |
.uk-navbar-dropdown-width-3 | 3-column navbar dropdown | uk-navbar-dropdown uk-navbar-dropdown-width-3 |
.uk-navbar-dropdown-width-4 | 4-column navbar dropdown | uk-navbar-dropdown uk-navbar-dropdown-width-4 |
.uk-navbar-dropdown-grid | Grid layout for navbar dropdown | <div class="uk-navbar-dropdown-grid"> |
.uk-dropdown-scrollable | Scrollable dropdown content | <div class="uk-dropdown-scrollable"> |
.uk-dropdown-right | Right-aligned sub-dropdown | <div class="uk-dropdown uk-dropdown-right"> |
Navbar Classes
| Class | Description | Usage |
|---|---|---|
.uk-navbar-container | Navbar container | <nav class="uk-navbar-container"> |
.uk-navbar | Base navbar class | uk-navbar-container uk-navbar |
.uk-navbar-nav | Navbar navigation list | <ul class="uk-navbar-nav"> |
.uk-navbar-left | Left-aligned navbar section | <div class="uk-navbar-left"> |
.uk-navbar-right | Right-aligned navbar section | <div class="uk-navbar-right"> |
.uk-navbar-center | Center-aligned navbar section | <div class="uk-navbar-center"> |
.uk-navbar-item | Navbar item | <a class="uk-navbar-item"> |
.uk-navbar-toggle | Navbar toggle button | <a class="uk-navbar-toggle"> |
JavaScript API & Interactive Features
Dropdown JavaScript Methods & Events
// Dropdown component initialization
const dropdown = UIkit.dropdown(element, {
pos: 'bottom-left', // Position
mode: 'hover', // Trigger mode
delayShow: 0, // Delay before showing
delayHide: 800, // Delay before hiding
animation: 'uk-animation-fade', // Animation
duration: 200, // Animation duration
offset: 0, // Offset from trigger
toggle: true, // Toggle on click
boundary: window, // Boundary element
boundaryAlign: false, // Align within boundary
flip: true, // Flip if out of viewport
clsDrop: 'uk-drop', // Drop class
clsDropShow: 'uk-open' // Show class
});
// Navbar initialization
const navbar = UIkit.navbar(element, {
align: 'left', // Alignment
mode: 'click', // Trigger mode
delayShow: 0, // Delay before showing
delayHide: 800, // Delay before hiding
boundary: window, // Boundary element
offset: 0, // Offset
dropbar: false, // Enable dropbar
dropbarMode: 'slide' // Dropbar animation
});
// Dropdown methods
dropdown.show(); // Show the dropdown
dropdown.hide(); // Hide the dropdown
dropdown.toggle(); // Toggle show/hide
// Dropdown events
dropdownElement.addEventListener('show', function(event) {
console.log('Dropdown showing:', event.detail);
});
dropdownElement.addEventListener('shown', function(event) {
console.log('Dropdown shown:', event.detail);
});
dropdownElement.addEventListener('hide', function(event) {
console.log('Dropdown hiding:', event.detail);
});
dropdownElement.addEventListener('hidden', function(event) {
console.log('Dropdown hidden:', event.detail);
});
// Dynamic dropdown management
const dropdownManager = {
dropdowns: [],
initDropdown: function(dropdownId, options = {}) {
const dropdownElement = document.getElementById(dropdownId);
if (!dropdownElement) return null;
const dropdown = UIkit.dropdown(dropdownElement, options);
this.dropdowns.push({ id: dropdownId, element: dropdownElement, instance: dropdown });
return dropdown;
},
showDropdown: function(dropdownId) {
const dropdown = this.dropdowns.find(d => d.id === dropdownId);
if (dropdown) {
dropdown.instance.show();
}
},
hideDropdown: function(dropdownId) {
const dropdown = this.dropdowns.find(d => d.id === dropdownId);
if (dropdown) {
dropdown.instance.hide();
}
},
toggleDropdown: function(dropdownId) {
const dropdown = this.dropdowns.find(d => d.id === dropdownId);
if (dropdown) {
dropdown.instance.toggle();
}
},
updateDropdownContent: function(dropdownId, content) {
const dropdown = this.dropdowns.find(d => d.id === dropdownId);
if (dropdown) {
dropdown.element.innerHTML = content;
}
},
destroyDropdown: function(dropdownId) {
const index = this.dropdowns.findIndex(d => d.id === dropdownId);
if (index > -1) {
const dropdown = this.dropdowns[index];
dropdown.instance.$destroy();
this.dropdowns.splice(index, 1);
}
}
};
// Initialize dropdowns
dropdownManager.initDropdown('userMenu', {
pos: 'bottom-justify',
mode: 'click'
});
dropdownManager.initDropdown('notifications', {
pos: 'bottom-right',
mode: 'click',
animation: 'uk-animation-slide-top-small'
});
// Example: Show dropdown on button click
document.getElementById('showMenuBtn').addEventListener('click', function() {
dropdownManager.showDropdown('userMenu');
});
// Example: Update dropdown content dynamically
document.getElementById('updateContentBtn').addEventListener('click', function() {
const newContent = `
<div class="uk-card uk-card-body uk-card-default">
<h3>Updated Content</h3>
<p>This content was updated dynamically.</p>
</div>
`;
dropdownManager.updateDropdownContent('userMenu', newContent);
});
// Navbar management
const navbarManager = {
navbars: [],
initNavbar: function(navbarId, options = {}) {
const navbarElement = document.getElementById(navbarId);
if (!navbarElement) return null;
const navbar = UIkit.navbar(navbarElement, options);
this.navbars.push({ id: navbarId, element: navbarElement, instance: navbar });
return navbar;
},
toggleNavbar: function(navbarId) {
const navbar = this.navbars.find(n => n.id === navbarId);
if (navbar) {
// UIKit doesn't have direct toggle method for navbar
const isActive = navbar.element.classList.contains('uk-open');
if (isActive) {
UIkit.drop(navbar.element.querySelector('.uk-navbar-dropdown')).hide();
} else {
UIkit.drop(navbar.element.querySelector('.uk-navbar-dropdown')).show();
}
}
}
};
// Initialize navbar
navbarManager.initNavbar('mainNavbar', {
align: 'center',
mode: 'hover'
});
// Dropdown positioning helper
const dropdownPositioning = {
calculatePosition: function(triggerElement, dropdownElement, position = 'bottom-left') {
const triggerRect = triggerElement.getBoundingClientRect();
const dropdownRect = dropdownElement.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let top, left;
switch(position) {
case 'bottom-left':
top = triggerRect.bottom;
left = triggerRect.left;
break;
case 'bottom-center':
top = triggerRect.bottom;
left = triggerRect.left + (triggerRect.width - dropdownRect.width) / 2;
break;
case 'bottom-right':
top = triggerRect.bottom;
left = triggerRect.right - dropdownRect.width;
break;
case 'top-left':
top = triggerRect.top - dropdownRect.height;
left = triggerRect.left;
break;
case 'top-center':
top = triggerRect.top - dropdownRect.height;
left = triggerRect.left + (triggerRect.width - dropdownRect.width) / 2;
break;
case 'top-right':
top = triggerRect.top - dropdownRect.height;
left = triggerRect.right - dropdownRect.width;
break;
case 'left-center':
top = triggerRect.top + (triggerRect.height - dropdownRect.height) / 2;
left = triggerRect.left - dropdownRect.width;
break;
case 'right-center':
top = triggerRect.top + (triggerRect.height - dropdownRect.height) / 2;
left = triggerRect.right;
break;
}
// Adjust if out of viewport
if (left < 0) left = 0;
if (left + dropdownRect.width > viewportWidth) {
left = viewportWidth - dropdownRect.width;
}
if (top < 0) top = 0;
if (top + dropdownRect.height > viewportHeight) {
top = viewportHeight - dropdownRect.height;
}
return { top, left };
},
repositionDropdown: function(dropdownId) {
const dropdown = dropdownManager.dropdowns.find(d => d.id === dropdownId);
if (!dropdown) return;
const trigger = document.querySelector(`[aria-controls="${dropdownId}"]`);
if (!trigger) return;
const position = dropdown.instance.pos || 'bottom-left';
const coords = this.calculatePosition(trigger, dropdown.element, position);
dropdown.element.style.position = 'fixed';
dropdown.element.style.top = `${coords.top}px`;
dropdown.element.style.left = ``${coords.left}px`;
dropdown.element.style.zIndex = '1040';
}
};
// Reposition dropdowns on window resize
window.addEventListener('resize', function() {
dropdownManager.dropdowns.forEach(dropdown => {
if (dropdown.instance.isActive()) {
dropdownPositioning.repositionDropdown(dropdown.id);
}
});
});
// Keyboard navigation for dropdowns
const dropdownNavigation = {
currentIndex: -1,
currentDropdown: null,
init: function(dropdownId) {
const dropdown = document.getElementById(dropdownId);
if (!dropdown) return;
const items = dropdown.querySelectorAll('.uk-dropdown-nav li > a');
dropdown.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowDown':
e.preventDefault();
this.navigateNext(items);
break;
case 'ArrowUp':
e.preventDefault();
this.navigatePrevious(items);
break;
case 'Enter':
if (this.currentIndex > -1) {
items[this.currentIndex].click();
}
break;
case 'Escape':
UIkit.dropdown(dropdown).hide();
break;
}
});
items.forEach((item, index) => {
item.addEventListener('focus', () => {
this.currentIndex = index;
});
item.addEventListener('mouseenter', () => {
this.currentIndex = index;
items.forEach(i => i.classList.remove('uk-active'));
item.classList.add('uk-active');
});
});
},
navigateNext: function(items) {
if (items.length === 0) return;
this.currentIndex = (this.currentIndex + 1) % items.length;
items[this.currentIndex].focus();
items.forEach(i => i.classList.remove('uk-active'));
items[this.currentIndex].classList.add('uk-active');
},
navigatePrevious: function(items) {
if (items.length === 0) return;
this.currentIndex = (this.currentIndex - 1 + items.length) % items.length;
items[this.currentIndex].focus();
items.forEach(i => i.classList.remove('uk-active'));
items[this.currentIndex].classList.add('uk-active');
}
};
// Initialize dropdown navigation
document.addEventListener('DOMContentLoaded', function() {
dropdownNavigation.init('userDropdown');
dropdownNavigation.init('settingsDropdown');
});
// Dropdown with AJAX content loading
const ajaxDropdown = {
loadContent: function(dropdownId, url) {
const dropdown = dropdownManager.dropdowns.find(d => d.id === dropdownId);
if (!dropdown) return;
// Show loading state
dropdown.element.innerHTML = `
<div class="uk-card uk-card-body uk-card-default">
<div class="uk-text-center">
<div uk-spinner></div>
<p class="uk-margin-small-top">Loading...</p>
</div>
</div>
`;
// Fetch content
fetch(url)
.then(response => response.text())
.then(html => {
dropdown.element.innerHTML = html;
UIkit.update(dropdown.element);
})
.catch(error => {
dropdown.element.innerHTML = `
<div class="uk-card uk-card-body uk-card-default">
<div class="uk-alert-danger" uk-alert>
<p>Failed to load content. Please try again.</p>
</div>
</div>
`;
});
}
};
// Example usage
document.getElementById('loadUserDataBtn').addEventListener('click', function() {
ajaxDropdown.loadContent('userMenu', '/api/user-data');
});
// Dropdown with form submission
const dropdownFormHandler = {
init: function(dropdownId, formSelector) {
const dropdown = dropdownManager.dropdowns.find(d => d.id === dropdownId);
if (!dropdown) return;
const form = dropdown.element.querySelector(formSelector);
if (!form) return;
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(form);
const submitBtn = form.querySelector('[type="submit"]');
const originalText = submitBtn.textContent;
// Show loading state
submitBtn.disabled = true;
submitBtn.innerHTML = `
<span uk-spinner="ratio: 0.5"></span>
Processing...
`;
// Simulate API call
setTimeout(() => {
// Reset form
form.reset();
submitBtn.disabled = false;
submitBtn.textContent = originalText;
// Show success message
const successMsg = `
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>Form submitted successfully!</p>
</div>
`;
dropdown.element.insertAdjacentHTML('afterbegin', successMsg);
// Hide dropdown after delay
setTimeout(() => {
dropdown.instance.hide();
}, 2000);
}, 1500);
});
}
};
// Initialize form handler
dropdownFormHandler.init('contactFormDropdown', '#contactForm');Best Practices for Dropdown Components:
- Always provide keyboard navigation for dropdowns (Arrow keys, Enter, Escape)
- Ensure proper focus management when dropdown opens/closes
- Use semantic HTML structure with appropriate ARIA attributes (aria-expanded, aria-haspopup)
- Implement proper screen reader support
- Add sufficient contrast between dropdown background and text
- Use appropriate positioning based on available screen space
- Implement boundary checking to prevent dropdowns from appearing off-screen
- Add smooth animations for better user experience
- Use appropriate trigger modes (hover vs click) based on context and device
- Provide clear visual feedback when dropdowns are interactive
- Implement touch-friendly sizes for mobile devices
- Use lazy loading for content-heavy dropdowns
- Add proper error states for failed content loading
- Implement proper z-index stacking context
- Test with various input methods (mouse, keyboard, touch)
- Consider implementing prefers-reduced-motion for animations
- Add close buttons for modal-like dropdowns on mobile
- Ensure dropdowns are accessible via keyboard tab navigation
- Use descriptive labels for screen reader users
- Implement proper focus trapping within dropdowns when needed