Flex Component
Flex Component: UIKit provides a comprehensive flexbox utility system for creating modern, responsive layouts. It includes flex containers, direction control, alignment utilities, and responsive flexbox classes that work across all devices.
Live Examples
1. Basic Flex Containers
Example Preview
Basic Flex Row
Item 1
Item 2
Item 3
Flex Column
Item 1
Item 2
Item 3
Flex Wrap
Item 1
Item 2
Item 3
Item 4
Item 5
2. Flex Alignment & Justification
Example Preview
Horizontal Alignment (Justify Content)
Left
Item
Center
Item
Right
Item
Between
Left
Right
Around
Item 1
Item 2
Vertical Alignment (Align Items)
Stretch
Stretched
Top
Top
Middle
Middle
Bottom
Bottom
Center Both Directions
Centered Horizontally & Vertically
3. Flex Item Properties
Example Preview
Flex Grow & Shrink
.uk-flex-none.uk-flex-1 (Grows).uk-flex-1 (Grows equally).uk-flex-first (Order: -1)Item 2 (Default order)
.uk-flex-last (Order: 999)Auto & Expand Width
.uk-width-auto.uk-width-autoFlex Order Classes
Order First
Order Last
Order 1
Order 2
4. Responsive Flex Utilities
Example Preview
Responsive Flex Direction
Item 1
Item 2
Item 3
Responsive Alignment
Responsive Alignment
Responsive Flex Wrap
Item 1
Item 2
Item 3
Item 4
5. Real-World Flex Layouts
Example Preview
Navigation Bar
Logo
Card with Flex Layout
Image/Icon
Card Title
Card description with some content that might wrap to multiple lines.
$29.99
Dashboard Widgets
123
Users
456
Sales
78%
Growth
$9,999
Revenue
Flex Classes Reference
Core Flex Container Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex | Display flex container | display: flex |
.uk-inline-flex | Display inline-flex container | display: inline-flex |
.uk-flex-inline | Inline flex container | display: inline-flex |
Flex Direction Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex-row | Flex direction row (default) | flex-direction: row |
.uk-flex-row-reverse | Flex direction row reverse | flex-direction: row-reverse |
.uk-flex-column | Flex direction column | flex-direction: column |
.uk-flex-column-reverse | Flex direction column reverse | flex-direction: column-reverse |
Flex Wrap Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex-nowrap | No wrapping (default) | flex-wrap: nowrap |
.uk-flex-wrap | Wrap items | flex-wrap: wrap |
.uk-flex-wrap-reverse | Wrap items in reverse | flex-wrap: wrap-reverse |
Justify Content Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex-left | Justify content flex-start | justify-content: flex-start |
.uk-flex-center | Justify content center | justify-content: center |
.uk-flex-right | Justify content flex-end | justify-content: flex-end |
.uk-flex-between | Justify content space-between | justify-content: space-between |
.uk-flex-around | Justify content space-around | justify-content: space-around |
Align Items Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex-stretch | Align items stretch (default) | align-items: stretch |
.uk-flex-top | Align items flex-start | align-items: flex-start |
.uk-flex-middle | Align items center | align-items: center |
.uk-flex-bottom | Align items flex-end | align-items: flex-end |
Flex Item Classes
| Class | Description | CSS Equivalent |
|---|---|---|
.uk-flex-none | Flex: none | flex: none |
.uk-flex-1 | Flex: 1 1 0% | flex: 1 |
.uk-flex-auto | Flex: auto | flex: auto |
.uk-flex-first | Order: -1 | order: -1 |
.uk-flex-last | Order: 999 | order: 999 |
JavaScript API & Dynamic Flex
Dynamic Flex Control with JavaScript
// Flex container manager
const flexManager = {
// Initialize flex container
initContainer: function(element, options = {}) {
const defaults = {
direction: 'row',
wrap: 'nowrap',
justify: 'flex-start',
align: 'stretch'
};
const settings = { ...defaults, ...options };
// Set basic flex class
element.classList.add('uk-flex');
// Set direction
this.setDirection(element, settings.direction);
// Set wrap
this.setWrap(element, settings.wrap);
// Set justification
this.setJustify(element, settings.justify);
// Set alignment
this.setAlign(element, settings.align);
return element;
},
// Set flex direction
setDirection: function(element, direction) {
const directions = ['row', 'row-reverse', 'column', 'column-reverse'];
const directionClasses = directions.map(dir => `uk-flex-${dir}`);
element.classList.remove(...directionClasses);
if (direction !== 'row') { // row is default
element.classList.add(`uk-flex-${direction}`);
}
return element;
},
// Set flex wrap
setWrap: function(element, wrap) {
const wraps = ['nowrap', 'wrap', 'wrap-reverse'];
const wrapClasses = wraps.map(w => `uk-flex-${w}`);
element.classList.remove(...wrapClasses);
if (wrap !== 'nowrap') { // nowrap is default
element.classList.add(`uk-flex-${wrap}`);
}
return element;
},
// Set justify content
setJustify: function(element, justify) {
const justifyOptions = {
'flex-start': 'uk-flex-left',
'center': 'uk-flex-center',
'flex-end': 'uk-flex-right',
'space-between': 'uk-flex-between',
'space-around': 'uk-flex-around'
};
const currentClasses = Object.values(justifyOptions);
element.classList.remove(...currentClasses);
if (justify !== 'flex-start') { // flex-start is default
const justifyClass = justifyOptions[justify];
if (justifyClass) {
element.classList.add(justifyClass);
}
}
return element;
},
// Set align items
setAlign: function(element, align) {
const alignOptions = {
'stretch': 'uk-flex-stretch',
'flex-start': 'uk-flex-top',
'center': 'uk-flex-middle',
'flex-end': 'uk-flex-bottom'
};
const currentClasses = Object.values(alignOptions);
element.classList.remove(...currentClasses);
if (align !== 'stretch') { // stretch is default
const alignClass = alignOptions[align];
if (alignClass) {
element.classList.add(alignClass);
}
}
return element;
},
// Toggle flex properties
toggleDirection: function(element) {
const currentDirection = this.getCurrentDirection(element);
const newDirection = currentDirection === 'row' ? 'column' : 'row';
return this.setDirection(element, newDirection);
},
toggleWrap: function(element) {
const currentWrap = this.getCurrentWrap(element);
const newWrap = currentWrap === 'nowrap' ? 'wrap' : 'nowrap';
return this.setWrap(element, newWrap);
},
// Get current properties
getCurrentDirection: function(element) {
if (element.classList.contains('uk-flex-column')) return 'column';
if (element.classList.contains('uk-flex-column-reverse')) return 'column-reverse';
if (element.classList.contains('uk-flex-row-reverse')) return 'row-reverse';
return 'row';
},
getCurrentWrap: function(element) {
if (element.classList.contains('uk-flex-wrap')) return 'wrap';
if (element.classList.contains('uk-flex-wrap-reverse')) return 'wrap-reverse';
return 'nowrap';
},
// Responsive flex utilities
responsiveFlex: function(element, breakpoints = {}) {
const updateFlex = () => {
const width = window.innerWidth;
// Default (mobile)
let direction = breakpoints.default?.direction || 'column';
let justify = breakpoints.default?.justify || 'flex-start';
// Apply breakpoint overrides
if (width >= 640 && breakpoints.s) {
direction = breakpoints.s.direction || direction;
justify = breakpoints.s.justify || justify;
}
if (width >= 960 && breakpoints.m) {
direction = breakpoints.m.direction || direction;
justify = breakpoints.m.justify || justify;
}
if (width >= 1200 && breakpoints.l) {
direction = breakpoints.l.direction || direction;
justify = breakpoints.l.justify || justify;
}
this.setDirection(element, direction);
this.setJustify(element, justify);
};
// Initial update
updateFlex();
// Update on resize
window.addEventListener('resize', updateFlex);
return {
destroy: () => {
window.removeEventListener('resize', updateFlex);
}
};
},
// Flex item management
manageItems: function(container) {
return {
addItem: function(content, options = {}) {
const item = document.createElement('div');
item.className = options.className || '';
item.innerHTML = content;
// Apply flex item properties
if (options.flex) {
item.classList.add(`uk-flex-${options.flex}`);
}
if (options.order) {
item.classList.add(`uk-flex-order-${options.order}`);
}
if (options.first) {
item.classList.add('uk-flex-first');
}
if (options.last) {
item.classList.add('uk-flex-last');
}
container.appendChild(item);
return item;
},
removeItem: function(index) {
const items = container.children;
if (items[index]) {
container.removeChild(items[index]);
return true;
}
return false;
},
reorderItems: function(newOrder) {
const items = Array.from(container.children);
const fragment = document.createDocumentFragment();
newOrder.forEach(index => {
if (items[index]) {
fragment.appendChild(items[index]);
}
});
container.innerHTML = '';
container.appendChild(fragment);
},
distributeItems: function() {
const items = container.children;
const itemCount = items.length;
Array.from(items).forEach((item, index) => {
item.classList.remove('uk-flex-1', 'uk-flex-auto', 'uk-flex-none');
if (itemCount <= 3) {
item.classList.add('uk-flex-1');
} else if (itemCount <= 6) {
item.classList.add('uk-flex-auto');
} else {
item.classList.add('uk-flex-none');
}
});
}
};
}
};
// Example usage
const flexContainer = document.getElementById('myFlexContainer');
const manager = flexManager.initContainer(flexContainer, {
direction: 'column',
wrap: 'wrap',
justify: 'space-between',
align: 'center'
});
// Toggle direction on click
flexContainer.addEventListener('click', () => {
flexManager.toggleDirection(flexContainer);
});
// Responsive flex
const responsiveInstance = flexManager.responsiveFlex(flexContainer, {
default: { direction: 'column', justify: 'center' },
s: { direction: 'row', justify: 'space-between' },
m: { direction: 'row', justify: 'space-around' }
});
// Manage items
const itemsManager = flexManager.manageItems(flexContainer);
itemsManager.addItem('<div>New Item</div>', {
flex: '1',
order: 'first'
});
// Flex animations
const flexAnimations = {
slideIn: function(element, direction = 'left') {
element.style.opacity = '0';
element.style.transform = `translateX(${direction === 'left' ? '-100%' : '100%'})`;
element.style.transition = 'opacity 0.3s, transform 0.3s';
// Trigger animation
requestAnimationFrame(() => {
element.style.opacity = '1';
element.style.transform = 'translateX(0)';
});
// Clean up
setTimeout(() => {
element.style.transition = '';
}, 300);
},
fadeIn: function(element) {
element.style.opacity = '0';
element.style.transition = 'opacity 0.3s';
requestAnimationFrame(() => {
element.style.opacity = '1';
});
setTimeout(() => {
element.style.transition = '';
}, 300);
},
staggerChildren: function(container, staggerDelay = 100) {
const children = container.children;
Array.from(children).forEach((child, index) => {
child.style.opacity = '0';
child.style.transform = 'translateY(20px)';
child.style.transition = `opacity 0.3s ${index * staggerDelay}ms, transform 0.3s ${index * staggerDelay}ms`;
setTimeout(() => {
child.style.opacity = '1';
child.style.transform = 'translateY(0)';
}, 10);
});
// Clean up
setTimeout(() => {
Array.from(children).forEach(child => {
child.style.transition = '';
});
}, 300 + (children.length * staggerDelay));
},
reorderAnimation: function(container, newOrder) {
const items = Array.from(container.children);
const fragment = document.createDocumentFragment();
// Animate out
items.forEach(item => {
item.style.transition = 'transform 0.3s, opacity 0.3s';
item.style.transform = 'scale(0.8)';
item.style.opacity = '0.5';
});
// Reorder
setTimeout(() => {
newOrder.forEach(index => {
if (items[index]) {
fragment.appendChild(items[index]);
}
});
container.innerHTML = '';
container.appendChild(fragment);
// Animate in
const newItems = container.children;
Array.from(newItems).forEach((item, index) => {
item.style.transform = 'scale(1)';
item.style.opacity = '1';
});
// Clean up
setTimeout(() => {
Array.from(newItems).forEach(item => {
item.style.transition = '';
item.style.transform = '';
item.style.opacity = '';
});
}, 300);
}, 300);
}
};
// Example: Animate flex items
const animatedContainer = document.getElementById('animatedFlex');
flexAnimations.staggerChildren(animatedContainer, 150);
// Flex layout builder
class FlexLayoutBuilder {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.layouts = [];
this.currentLayout = 0;
this.initialize();
}
initialize() {
// Create control panel
this.createControls();
// Load default layouts
this.loadDefaultLayouts();
// Apply first layout
this.applyLayout(0);
}
createControls() {
const controls = document.createElement('div');
controls.className = 'uk-flex uk-flex-between uk-margin-bottom';
controls.innerHTML = `
<div class="uk-button-group">
<button class="uk-button uk-button-default" id="prevLayout">Previous</button>
<button class="uk-button uk-button-default" id="nextLayout">Next</button>
</div>
<div class="uk-button-group">
<button class="uk-button uk-button-primary" id="saveLayout">Save</button>
<button class="uk-button uk-button-danger" id="resetLayout">Reset</button>
</div>
`;
this.container.parentNode.insertBefore(controls, this.container);
// Add event listeners
document.getElementById('prevLayout').addEventListener('click', () => this.prevLayout());
document.getElementById('nextLayout').addEventListener('click', () => this.nextLayout());
document.getElementById('saveLayout').addEventListener('click', () => this.saveLayout());
document.getElementById('resetLayout').addEventListener('click', () => this.resetLayout());
}
loadDefaultLayouts() {
this.layouts = [
{
name: 'Horizontal Center',
direction: 'row',
justify: 'center',
align: 'center',
wrap: 'nowrap',
items: 3
},
{
name: 'Vertical Stack',
direction: 'column',
justify: 'flex-start',
align: 'stretch',
wrap: 'nowrap',
items: 4
},
{
name: 'Space Between',
direction: 'row',
justify: 'space-between',
align: 'middle',
wrap: 'wrap',
items: 5
},
{
name: 'Card Grid',
direction: 'row',
justify: 'space-around',
align: 'stretch',
wrap: 'wrap',
items: 6
}
];
}
applyLayout(index) {
if (index < 0 || index >= this.layouts.length) return;
this.currentLayout = index;
const layout = this.layouts[index];
// Clear container
this.container.innerHTML = '';
// Apply container styles
this.container.className = 'uk-flex';
flexManager.setDirection(this.container, layout.direction);
flexManager.setJustify(this.container, layout.justify);
flexManager.setAlign(this.container, layout.align);
flexManager.setWrap(this.container, layout.wrap);
// Add items
for (let i = 0; i < layout.items; i++) {
const item = document.createElement('div');
item.className = 'uk-padding uk-background-muted uk-margin-small';
item.textContent = `Item ${i + 1}`;
item.style.minWidth = '100px';
item.style.minHeight = '50px';
this.container.appendChild(item);
}
// Update UI
this.updateStatus();
}
prevLayout() {
let newIndex = this.currentLayout - 1;
if (newIndex < 0) newIndex = this.layouts.length - 1;
this.applyLayout(newIndex);
}
nextLayout() {
let newIndex = this.currentLayout + 1;
if (newIndex >= this.layouts.length) newIndex = 0;
this.applyLayout(newIndex);
}
saveLayout() {
const layout = {
name: prompt('Enter layout name:', `Layout ${this.layouts.length + 1}`),
direction: flexManager.getCurrentDirection(this.container),
justify: this.getCurrentJustify(),
align: this.getCurrentAlign(),
wrap: flexManager.getCurrentWrap(this.container),
items: this.container.children.length
};
if (layout.name) {
this.layouts.push(layout);
this.applyLayout(this.layouts.length - 1);
}
}
resetLayout() {
this.applyLayout(0);
}
getCurrentJustify() {
if (this.container.classList.contains('uk-flex-center')) return 'center';
if (this.container.classList.contains('uk-flex-right')) return 'flex-end';
if (this.container.classList.contains('uk-flex-between')) return 'space-between';
if (this.container.classList.contains('uk-flex-around')) return 'space-around';
return 'flex-start';
}
getCurrentAlign() {
if (this.container.classList.contains('uk-flex-top')) return 'flex-start';
if (this.container.classList.contains('uk-flex-middle')) return 'center';
if (this.container.classList.contains('uk-flex-bottom')) return 'flex-end';
return 'stretch';
}
updateStatus() {
const layout = this.layouts[this.currentLayout];
const status = document.getElementById('layoutStatus') || this.createStatusElement();
status.textContent = `${layout.name} (${this.currentLayout + 1}/${this.layouts.length})`;
}
createStatusElement() {
const status = document.createElement('div');
status.id = 'layoutStatus';
status.className = 'uk-text-center uk-text-meta uk-margin-top';
this.container.parentNode.appendChild(status);
return status;
}
}
// Example usage
const layoutBuilder = new FlexLayoutBuilder('flexLayoutDemo');
// Flex form layout system
const flexFormSystem = {
createFormLayout: function(formId, layout = 'vertical') {
const form = document.getElementById(formId);
if (!form) return;
form.classList.add('uk-flex', 'uk-flex-column');
if (layout === 'horizontal') {
form.classList.remove('uk-flex-column');
form.classList.add('uk-flex-row', 'uk-flex-wrap', 'uk-flex-middle');
} else if (layout === 'grid') {
form.classList.remove('uk-flex-column');
form.classList.add('uk-flex-row', 'uk-flex-wrap', 'uk-flex-between');
}
return form;
},
addFormGroup: function(form, label, inputType, options = {}) {
const group = document.createElement('div');
group.className = `uk-margin ${options.className || ''}`;
if (form.classList.contains('uk-flex-row')) {
group.classList.add('uk-width-1-2@s');
}
const labelEl = document.createElement('label');
labelEl.className = 'uk-form-label';
labelEl.textContent = label;
labelEl.htmlFor = options.id || `input-${Date.now()}`;
const input = document.createElement('input');
input.className = 'uk-input';
input.type = inputType;
input.id = options.id || labelEl.htmlFor;
input.name = options.name || input.id;
if (options.placeholder) {
input.placeholder = options.placeholder;
}
if (options.required) {
input.required = true;
}
group.appendChild(labelEl);
group.appendChild(input);
form.appendChild(group);
return group;
},
createButtonGroup: function(buttons, align = 'right') {
const group = document.createElement('div');
group.className = `uk-flex uk-flex-${align} uk-margin-top`;
buttons.forEach(btn => {
const button = document.createElement('button');
button.type = btn.type || 'button';
button.className = `uk-button ${btn.className || 'uk-button-default'}`;
button.textContent = btn.text;
if (btn.onClick) {
button.addEventListener('click', btn.onClick);
}
group.appendChild(button);
});
return group;
},
responsiveForm: function(form, breakpoints = {}) {
const updateForm = () => {
const width = window.innerWidth;
// Remove all layout classes
form.classList.remove('uk-flex-column', 'uk-flex-row', 'uk-flex-wrap', 'uk-flex-middle', 'uk-flex-between');
// Apply base layout
form.classList.add('uk-flex');
// Apply breakpoint layout
if (width < 640 && breakpoints.default) {
form.classList.add('uk-flex-column');
} else if (width >= 640 && width < 960 && breakpoints.s) {
form.classList.add('uk-flex-row', 'uk-flex-wrap');
if (breakpoints.s.align === 'middle') {
form.classList.add('uk-flex-middle');
}
} else if (width >= 960 && breakpoints.m) {
form.classList.add('uk-flex-row', 'uk-flex-wrap', 'uk-flex-between');
}
};
updateForm();
window.addEventListener('resize', updateForm);
return {
destroy: () => window.removeEventListener('resize', updateForm)
};
}
};
// Example: Create a responsive form
const myForm = flexFormSystem.createFormLayout('myForm', 'vertical');
// Add form groups
flexFormSystem.addFormGroup(myForm, 'Name', 'text', {
placeholder: 'Enter your name',
required: true
});
flexFormSystem.addFormGroup(myForm, 'Email', 'email', {
placeholder: 'Enter your email',
required: true
});
// Add button group
const buttonGroup = flexFormSystem.createButtonGroup([
{ text: 'Cancel', className: 'uk-button-default', onClick: () => console.log('Cancelled') },
{ text: 'Submit', className: 'uk-button-primary', type: 'submit' }
], 'between');
myForm.appendChild(buttonGroup);
// Make form responsive
const formResponsive = flexFormSystem.responsiveForm(myForm, {
default: { layout: 'vertical' },
s: { layout: 'horizontal', align: 'middle' },
m: { layout: 'grid' }
});Complete Real-World Examples
Responsive Header with Flex
<!-- Responsive Header -->
<header class="uk-background-primary uk-light">
<div class="uk-container">
<div class="uk-flex uk-flex-between uk-flex-middle uk-padding">
<!-- Logo -->
<div class="uk-flex uk-flex-middle">
<a href="/" class="uk-logo uk-text-bold">
<span uk-icon="icon: happy; ratio: 1.5" class="uk-margin-small-right"></span>
BrandName
</a>
</div>
<!-- Desktop Navigation -->
<nav class="uk-visible@m">
<ul class="uk-flex uk-subnav uk-subnav-divider uk-margin-remove">
<li class="uk-active"><a href="#">Home</a></li>
<li><a href="#">Products</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
<!-- Right Side Actions -->
<div class="uk-flex uk-flex-middle">
<!-- Search -->
<div class="uk-inline uk-visible@m">
<span class="uk-form-icon" uk-icon="icon: search"></span>
<input class="uk-input uk-form-width-small" type="search" placeholder="Search...">
</div>
<!-- User Menu -->
<div class="uk-inline uk-margin-left">
<button class="uk-button uk-button-default">
<span uk-icon="icon: user" class="uk-margin-small-right"></span>
Account
</button>
<div uk-dropdown="mode: click">
<ul class="uk-nav uk-dropdown-nav">
<li><a href="#"><span uk-icon="icon: cog"></span> Settings</a></li>
<li><a href="#"><span uk-icon="icon: sign-out"></span> Logout</a></li>
</ul>
</div>
</div>
<!-- Mobile Menu Toggle -->
<button class="uk-button uk-button-default uk-hidden@m uk-margin-left" type="button" uk-toggle="target: #mobile-menu">
<span uk-icon="icon: menu"></span>
</button>
</div>
</div>
<!-- Mobile Menu -->
<div id="mobile-menu" hidden>
<div class="uk-padding">
<ul class="uk-nav uk-nav-default">
<li class="uk-active"><a href="#">Home</a></li>
<li><a href="#">Products</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
<li class="uk-nav-divider"></li>
<li>
<div class="uk-margin">
<input class="uk-input" type="search" placeholder="Search...">
</div>
</li>
</ul>
</div>
</div>
</div>
</header>
<script>
// Header functionality
class ResponsiveHeader {
constructor() {
this.header = document.querySelector('header');
this.mobileMenu = document.getElementById('mobile-menu');
this.menuToggle = document.querySelector('[uk-toggle="target: #mobile-menu"]');
this.initialize();
}
initialize() {
this.setupMobileMenu();
this.setupStickyHeader();
this.setupSearch();
}
setupMobileMenu() {
// Close menu when clicking outside
document.addEventListener('click', (e) => {
if (!this.mobileMenu.contains(e.target) &&
!this.menuToggle.contains(e.target) &&
!this.mobileMenu.hidden) {
UIkit.toggle(this.mobileMenu).toggle();
}
});
// Close menu on link click
this.mobileMenu.querySelectorAll('a').forEach(link => {
link.addEventListener('click', () => {
UIkit.toggle(this.mobileMenu).toggle();
});
});
}
setupStickyHeader() {
// Add sticky class on scroll
let lastScroll = 0;
window.addEventListener('scroll', () => {
const currentScroll = window.pageYOffset;
if (currentScroll > 100) {
this.header.classList.add('uk-sticky', 'uk-box-shadow-small');
} else {
this.header.classList.remove('uk-sticky', 'uk-box-shadow-small');
}
// Hide/show on scroll direction
if (currentScroll > lastScroll && currentScroll > 100) {
// Scrolling down
this.header.style.transform = 'translateY(-100%)';
} else {
// Scrolling up
this.header.style.transform = 'translateY(0)';
}
lastScroll = currentScroll;
});
// Smooth transition
this.header.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease';
}
setupSearch() {
const searchInput = document.querySelector('input[type="search"]');
const searchResults = document.createElement('div');
searchResults.className = 'uk-dropdown uk-dropdown-bottom uk-background-default uk-box-shadow-medium';
searchResults.style.width = searchInput.offsetWidth + 'px';
searchResults.hidden = true;
searchInput.parentNode.appendChild(searchResults);
// Show/hide results
searchInput.addEventListener('focus', () => {
searchResults.hidden = false;
this.updateSearchResults(''); // Show recent searches
});
searchInput.addEventListener('blur', () => {
setTimeout(() => {
searchResults.hidden = true;
}, 200);
});
// Live search
searchInput.addEventListener('input', (e) => {
this.updateSearchResults(e.target.value);
});
}
updateSearchResults(query) {
const searchResults = document.querySelector('.uk-dropdown');
if (!query) {
searchResults.innerHTML = `
<div class="uk-padding-small">
<div class="uk-text-small uk-text-muted">Recent searches</div>
<ul class="uk-list uk-list-divider uk-margin-small-top">
<li><a href="#" class="uk-link-text">Product A</a></li>
<li><a href="#" class="uk-link-text">Service B</a></li>
<li><a href="#" class="uk-link-text">Documentation</a></li>
</ul>
</div>
`;
} else {
// Simulated search results
searchResults.innerHTML = `
<div class="uk-padding-small">
<div class="uk-text-small uk-text-muted">Search results for "${query}"</div>
<ul class="uk-list uk-list-divider uk-margin-small-top">
<li><a href="#" class="uk-link-text">${query} Product</a></li>
<li><a href="#" class="uk-link-text">${query} Service</a></li>
<li><a href="#" class="uk-link-text">${query} Documentation</a></li>
</ul>
</div>
`;
}
}
}
// Initialize header
const header = new ResponsiveHeader();
// Responsive navigation adjustment
window.addEventListener('resize', () => {
const nav = document.querySelector('nav');
const rightActions = document.querySelector('.uk-flex-middle').lastElementChild;
if (window.innerWidth < 960) {
// Move search to mobile menu if needed
const searchContainer = document.querySelector('.uk-inline[uk-icon="icon: search"]');
if (searchContainer && searchContainer.parentNode === rightActions) {
const mobileMenu = document.getElementById('mobile-menu');
const searchClone = searchContainer.cloneNode(true);
searchClone.classList.remove('uk-visible@m');
mobileMenu.querySelector('.uk-nav').insertBefore(
searchClone,
mobileMenu.querySelector('.uk-nav-divider')
);
searchContainer.remove();
}
}
});
</script>E-commerce Product Grid with Flex
<!-- E-commerce Product Grid -->
<div class="uk-container uk-margin-top">
<!-- Filter & Sort Bar -->
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-bottom">
<div class="uk-flex uk-flex-middle">
<h1 class="uk-margin-remove">Products</h1>
<span class="uk-label uk-margin-left">24 items</span>
</div>
<div class="uk-flex uk-flex-middle">
<!-- View Toggle -->
<div class="uk-button-group uk-margin-right">
<button class="uk-button uk-button-default" id="gridView">
<span uk-icon="icon: grid"></span>
</button>
<button class="uk-button uk-button-default" id="listView">
<span uk-icon="icon: list"></span>
</button>
</div>
<!-- Sort Dropdown -->
<div class="uk-inline">
<button class="uk-button uk-button-default" type="button">
Sort by: <span id="sortText">Popular</span>
<span uk-icon="icon: triangle-down"></span>
</button>
<div uk-dropdown>
<ul class="uk-nav uk-dropdown-nav">
<li><a href="#" data-sort="popular">Popular</a></li>
<li><a href="#" data-sort="newest">Newest</a></li>
<li><a href="#" data-sort="price-low">Price: Low to High</a></li>
<li><a href="#" data-sort="price-high">Price: High to Low</a></li>
<li><a href="#" data-sort="rating">Highest Rated</a></li>
</ul>
</div>
</div>
</div>
</div>
<!-- Products Container -->
<div class="uk-flex uk-flex-wrap uk-flex-between" id="productsContainer">
<!-- Products will be dynamically loaded -->
</div>
<!-- Loading More -->
<div class="uk-text-center uk-margin-large-top" id="loadMoreContainer">
<button class="uk-button uk-button-default" id="loadMore">Load More Products</button>
</div>
</div>
<script>
// Product Grid Manager
class ProductGridManager {
constructor() {
this.products = [];
this.currentView = 'grid'; // 'grid' or 'list'
this.currentSort = 'popular';
this.currentPage = 1;
this.productsPerPage = 12;
this.isLoading = false;
this.initialize();
}
async initialize() {
await this.loadProducts();
this.setupEventListeners();
this.renderProducts();
}
async loadProducts() {
// Simulated API call
this.isLoading = true;
this.showLoading();
// Simulate delay
await new Promise(resolve => setTimeout(resolve, 500));
// Simulated product data
this.products = Array.from({ length: 24 }, (_, i) => ({
id: i + 1,
name: `Product ${i + 1}`,
description: `Description for product ${i + 1}. This is a great product with amazing features.`,
price: Math.floor(Math.random() * 1000) + 99,
rating: (Math.random() * 2 + 3).toFixed(1), // 3-5 stars
image: `https://picsum.photos/300/200?random=${i}`,
category: ['Electronics', 'Clothing', 'Home', 'Books'][Math.floor(Math.random() * 4)],
isNew: Math.random() > 0.7,
isSale: Math.random() > 0.5
}));
this.isLoading = false;
this.hideLoading();
}
setupEventListeners() {
// View toggle
document.getElementById('gridView').addEventListener('click', () => {
this.setView('grid');
document.getElementById('gridView').classList.add('uk-active');
document.getElementById('listView').classList.remove('uk-active');
});
document.getElementById('listView').addEventListener('click', () => {
this.setView('list');
document.getElementById('listView').classList.add('uk-active');
document.getElementById('gridView').classList.remove('uk-active');
});
// Sort dropdown
document.querySelectorAll('[data-sort]').forEach(item => {
item.addEventListener('click', (e) => {
e.preventDefault();
const sortType = e.target.dataset.sort;
this.setSort(sortType);
document.getElementById('sortText').textContent = e.target.textContent;
});
});
// Load more
document.getElementById('loadMore').addEventListener('click', () => {
this.loadMoreProducts();
});
}
setView(view) {
this.currentView = view;
this.renderProducts();
}
setSort(sortType) {
this.currentSort = sortType;
switch (sortType) {
case 'newest':
this.products.sort((a, b) => b.id - a.id);
break;
case 'price-low':
this.products.sort((a, b) => a.price - b.price);
break;
case 'price-high':
this.products.sort((a, b) => b.price - a.price);
break;
case 'rating':
this.products.sort((a, b) => b.rating - a.rating);
break;
default: // popular
this.products.sort((a, b) => b.id - a.id); // Simulated popularity
}
this.renderProducts();
}
renderProducts() {
const container = document.getElementById('productsContainer');
container.innerHTML = '';
// Calculate products to show
const startIndex = 0;
const endIndex = Math.min(this.currentPage * this.productsPerPage, this.products.length);
const productsToShow = this.products.slice(startIndex, endIndex);
// Set container classes based on view
container.className = '';
if (this.currentView === 'grid') {
container.classList.add('uk-flex', 'uk-flex-wrap', 'uk-flex-between');
productsToShow.forEach(product => {
const productElement = this.createGridProduct(product);
container.appendChild(productElement);
});
} else {
container.classList.add('uk-flex', 'uk-flex-column');
productsToShow.forEach(product => {
const productElement = this.createListProduct(product);
container.appendChild(productElement);
});
}
// Update load more button
this.updateLoadMoreButton();
}
createGridProduct(product) {
const div = document.createElement('div');
div.className = 'uk-width-1-2 uk-width-1-3@m uk-width-1-4@l uk-margin-bottom';
div.innerHTML = `
<div class="uk-card uk-card-default uk-card-hover">
<div class="uk-card-media-top">
<div class="uk-position-relative">
<img src="${product.image}" alt="${product.name}" class="uk-width-1-1">
${product.isNew ? '<div class="uk-position-top-right uk-label uk-label-success uk-margin-small-top uk-margin-small-right">NEW</div>' : ''}
${product.isSale ? '<div class="uk-position-top-left uk-label uk-label-danger uk-margin-small-top uk-margin-small-left">SALE</div>' : ''}
</div>
</div>
<div class="uk-card-body">
<h3 class="uk-card-title uk-text-small uk-margin-remove-bottom">${product.name}</h3>
<div class="uk-flex uk-flex-middle uk-margin-small-top">
<div class="uk-rating">
${this.renderStars(product.rating)}
</div>
<span class="uk-text-small uk-text-muted uk-margin-small-left">(${product.rating})</span>
</div>
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-top">
<div class="uk-text-bold uk-text-large">$${product.price}</div>
<button class="uk-button uk-button-primary uk-button-small" data-product-id="${product.id}">
<span uk-icon="icon: cart" class="uk-margin-small-right"></span>
Add
</button>
</div>
</div>
</div>
`;
// Add to cart functionality
div.querySelector('button').addEventListener('click', () => {
this.addToCart(product.id);
});
return div;
}
createListProduct(product) {
const div = document.createElement('div');
div.className = 'uk-card uk-card-default uk-card-body uk-margin-bottom';
div.innerHTML = `
<div class="uk-flex uk-flex-column uk-flex-row@m">
<div class="uk-width-1-1 uk-width-1-4@m">
<div class="uk-position-relative">
<img src="${product.image}" alt="${product.name}" class="uk-width-1-1">
${product.isNew ? '<div class="uk-position-top-right uk-label uk-label-success uk-margin-small-top uk-margin-small-right">NEW</div>' : ''}
</div>
</div>
<div class="uk-width-1-1 uk-width-3-4@m uk-padding-left@m">
<div class="uk-flex uk-flex-column uk-height-1-1">
<div class="uk-flex-1">
<h3 class="uk-card-title uk-margin-remove">${product.name}</h3>
<div class="uk-flex uk-flex-middle uk-margin-small-top">
<div class="uk-rating">
${this.renderStars(product.rating)}
</div>
<span class="uk-text-small uk-text-muted uk-margin-small-left">(${product.rating})</span>
<span class="uk-label uk-margin-small-left">${product.category}</span>
</div>
<p class="uk-text-muted uk-margin-small-top">${product.description}</p>
</div>
<div class="uk-flex uk-flex-between uk-flex-middle">
<div>
<div class="uk-text-bold uk-text-large">$${product.price}</div>
${product.isSale ? '<div class="uk-text-small uk-text-danger">Limited Time Offer</div>' : ''}
</div>
<div class="uk-flex uk-flex-middle">
<button class="uk-button uk-button-default uk-margin-small-right">
<span uk-icon="icon: heart"></span>
</button>
<button class="uk-button uk-button-primary" data-product-id="${product.id}">
<span uk-icon="icon: cart" class="uk-margin-small-right"></span>
Add to Cart
</button>
</div>
</div>
</div>
</div>
</div>
`;
// Add to cart functionality
div.querySelector('button[data-product-id]').addEventListener('click', () => {
this.addToCart(product.id);
});
return div;
}
renderStars(rating) {
const fullStars = Math.floor(rating);
const hasHalfStar = rating % 1 >= 0.5;
const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0);
let stars = '';
// Full stars
for (let i = 0; i < fullStars; i++) {
stars += '<span uk-icon="icon: star; ratio: 0.8" class="uk-text-warning"></span>';
}
// Half star
if (hasHalfStar) {
stars += '<span uk-icon="icon: star-half; ratio: 0.8" class="uk-text-warning"></span>';
}
// Empty stars
for (let i = 0; i < emptyStars; i++) {
stars += '<span uk-icon="icon: star; ratio: 0.8" class="uk-text-muted"></span>';
}
return stars;
}
addToCart(productId) {
const product = this.products.find(p => p.id === productId);
// Show notification
UIkit.notification({
message: `${product.name} added to cart!`,
status: 'success',
pos: 'top-right',
timeout: 3000
});
// Update cart count (simulated)
const cartCount = document.getElementById('cartCount') || this.createCartCount();
let currentCount = parseInt(cartCount.textContent) || 0;
cartCount.textContent = currentCount + 1;
// Animation
cartCount.classList.add('uk-animation-scale-up');
setTimeout(() => {
cartCount.classList.remove('uk-animation-scale-up');
}, 300);
}
createCartCount() {
const cartLink = document.querySelector('a[href="#cart"]');
if (!cartLink) return null;
const count = document.createElement('span');
count.id = 'cartCount';
count.className = 'uk-badge uk-position-top-right';
count.textContent = '0';
cartLink.appendChild(count);
return count;
}
async loadMoreProducts() {
if (this.isLoading) return;
this.isLoading = true;
const loadMoreBtn = document.getElementById('loadMore');
loadMoreBtn.disabled = true;
loadMoreBtn.innerHTML = '<span uk-spinner="ratio: 0.5"></span> Loading...';
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
this.currentPage++;
this.renderProducts();
loadMoreBtn.disabled = false;
loadMoreBtn.textContent = 'Load More Products';
this.isLoading = false;
}
updateLoadMoreButton() {
const loadMoreBtn = document.getElementById('loadMore');
const loadMoreContainer = document.getElementById('loadMoreContainer');
if (this.currentPage * this.productsPerPage >= this.products.length) {
loadMoreContainer.style.display = 'none';
} else {
loadMoreContainer.style.display = 'block';
}
}
showLoading() {
const container = document.getElementById('productsContainer');
container.innerHTML = `
<div class="uk-width-1-1 uk-text-center">
<div uk-spinner="ratio: 2"></div>
<p class="uk-text-muted uk-margin-small-top">Loading products...</p>
</div>
`;
}
hideLoading() {
// Handled in renderProducts
}
}
// Initialize product grid
const productGrid = new ProductGridManager();
// Set initial active view button
document.getElementById('gridView').classList.add('uk-active');
// Responsive adjustments
window.addEventListener('resize', () => {
const container = document.getElementById('productsContainer');
if (window.innerWidth < 640) {
// Force grid view on mobile
productGrid.setView('grid');
document.getElementById('gridView').classList.add('uk-active');
document.getElementById('listView').classList.remove('uk-active');
}
});
</script>Custom Flex Utilities
/* Custom Flex Utilities */
/* Flex Gap Utilities */
.uk-flex-gap-none { gap: 0; }
.uk-flex-gap-small { gap: 10px; }
.uk-flex-gap-medium { gap: 20px; }
.uk-flex-gap-large { gap: 30px; }
/* Responsive Flex Gap */
.uk-flex-gap-small@m { gap: 10px; }
.uk-flex-gap-medium@l { gap: 20px; }
.uk-flex-gap-large@xl { gap: 30px; }
/* Flex Basis Utilities */
.uk-flex-basis-auto { flex-basis: auto; }
.uk-flex-basis-0 { flex-basis: 0; }
.uk-flex-basis-25 { flex-basis: 25%; }
.uk-flex-basis-50 { flex-basis: 50%; }
.uk-flex-basis-75 { flex-basis: 75%; }
.uk-flex-basis-100 { flex-basis: 100%; }
/* Flex Shrink/Grow */
.uk-flex-shrink-0 { flex-shrink: 0; }
.uk-flex-shrink-1 { flex-shrink: 1; }
.uk-flex-grow-0 { flex-grow: 0; }
.uk-flex-grow-1 { flex-grow: 1; }
.uk-flex-grow-2 { flex-grow: 2; }
/* Advanced Flex Alignment */
.uk-flex-align-content-start { align-content: flex-start; }
.uk-flex-align-content-center { align-content: center; }
.uk-flex-align-content-end { align-content: flex-end; }
.uk-flex-align-content-between { align-content: space-between; }
.uk-flex-align-content-around { align-content: space-around; }
.uk-flex-align-content-stretch { align-content: stretch; }
/* Flex Self Alignment */
.uk-flex-self-auto { align-self: auto; }
.uk-flex-self-start { align-self: flex-start; }
.uk-flex-self-center { align-self: center; }
.uk-flex-self-end { align-self: flex-end; }
.uk-flex-self-stretch { align-self: stretch; }
.uk-flex-self-baseline { align-self: baseline; }
/* Flex Flow Shorthand */
.uk-flex-flow-row-nowrap { flex-flow: row nowrap; }
.uk-flex-flow-row-wrap { flex-flow: row wrap; }
.uk-flex-flow-column-nowrap { flex-flow: column nowrap; }
.uk-flex-flow-column-wrap { flex-flow: column wrap; }
/* Custom Flex Order */
.uk-flex-order-negative { order: -1; }
.uk-flex-order-0 { order: 0; }
.uk-flex-order-1 { order: 1; }
.uk-flex-order-2 { order: 2; }
.uk-flex-order-3 { order: 3; }
.uk-flex-order-4 { order: 4; }
.uk-flex-order-5 { order: 5; }
/* Flex Container Sizing */
.uk-flex-container-fluid { width: 100%; }
.uk-flex-container-fixed { width: 1200px; max-width: 100%; }
.uk-flex-container-small { width: 800px; max-width: 100%; }
.uk-flex-container-large { width: 1400px; max-width: 100%; }
/* Flex with Shadows */
.uk-flex-shadow { box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.uk-flex-shadow-hover { transition: box-shadow 0.3s; }
.uk-flex-shadow-hover:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.2); }
/* Flex Border Utilities */
.uk-flex-border { border: 1px solid #e5e5e5; }
.uk-flex-border-top { border-top: 1px solid #e5e5e5; }
.uk-flex-border-bottom { border-bottom: 1px solid #e5e5e5; }
.uk-flex-border-left { border-left: 1px solid #e5e5e5; }
.uk-flex-border-right { border-right: 1px solid #e5e5e5; }
/* Flex Spacing Utilities */
.uk-flex-space-between > * + * { margin-left: auto; }
.uk-flex-space-around > * { margin: 0 auto; }
/* Custom Flex Grid */
.uk-flex-grid {
display: flex;
flex-wrap: wrap;
margin: -10px;
}
.uk-flex-grid > * {
padding: 10px;
}
.uk-flex-grid-2 > * { width: 50%; }
.uk-flex-grid-3 > * { width: 33.333%; }
.uk-flex-grid-4 > * { width: 25%; }
.uk-flex-grid-5 > * { width: 20%; }
/* Responsive Flex Grid */
.uk-flex-grid-1-2 > * {
width: 100%;
}
@media (min-width: 640px) {
.uk-flex-grid-1-2 > * {
width: 50%;
}
}
@media (min-width: 960px) {
.uk-flex-grid-1-2 > * {
width: 33.333%;
}
}
/* Flex Masonry Layout */
.uk-flex-masonry {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 1000px;
}
.uk-flex-masonry > * {
break-inside: avoid;
margin-bottom: 20px;
}
/* Flex Animation Classes */
.uk-flex-animate {
transition: all 0.3s ease;
}
.uk-flex-slide-in {
animation: slideInFlex 0.5s ease;
}
@keyframes slideInFlex {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.uk-flex-fade-in {
animation: fadeInFlex 0.5s ease;
}
@keyframes fadeInFlex {
from { opacity: 0; }
to { opacity: 1; }
}
/* Flex Hover Effects */
.uk-flex-hover-scale {
transition: transform 0.3s;
}
.uk-flex-hover-scale:hover {
transform: scale(1.05);
}
.uk-flex-hover-lift {
transition: transform 0.3s, box-shadow 0.3s;
}
.uk-flex-hover-lift:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
/* Flex Color Utilities */
.uk-flex-bg-primary { background-color: #1e87f0; }
.uk-flex-bg-secondary { background-color: #222; }
.uk-flex-bg-success { background-color: #32d296; }
.uk-flex-bg-warning { background-color: #faa05a; }
.uk-flex-bg-danger { background-color: #f0506e; }
/* Flex Text Utilities */
.uk-flex-text-center > * { text-align: center; }
.uk-flex-text-left > * { text-align: left; }
.uk-flex-text-right > * { text-align: right; }
.uk-flex-text-justify > * { text-align: justify; }
/* Flex Overflow Utilities */
.uk-flex-overflow-auto { overflow: auto; }
.uk-flex-overflow-hidden { overflow: hidden; }
.uk-flex-overflow-scroll { overflow: scroll; }
.uk-flex-overflow-visible { overflow: visible; }
/* Flex Position Utilities */
.uk-flex-relative { position: relative; }
.uk-flex-absolute { position: absolute; }
.uk-flex-fixed { position: fixed; }
.uk-flex-sticky { position: sticky; }
/* Flex Z-index Utilities */
.uk-flex-z-0 { z-index: 0; }
.uk-flex-z-10 { z-index: 10; }
.uk-flex-z-20 { z-index: 20; }
.uk-flex-z-30 { z-index: 30; }
.uk-flex-z-40 { z-index: 40; }
.uk-flex-z-50 { z-index: 50; }
/* Custom Flex Variables */
:root {
--flex-gap-small: 10px;
--flex-gap-medium: 20px;
--flex-gap-large: 30px;
--flex-shadow: 0 2px 8px rgba(0,0,0,0.1);
--flex-shadow-hover: 0 4px 16px rgba(0,0,0,0.2);
}
.uk-flex-custom-gap { gap: var(--flex-gap-medium); }
.uk-flex-custom-shadow { box-shadow: var(--flex-shadow); }
.uk-flex-custom-shadow-hover:hover { box-shadow: var(--flex-shadow-hover); }
/* Usage Examples */
<div class="uk-flex uk-flex-gap-medium uk-flex-shadow">
<div class="uk-flex-1">Item 1</div>
<div class="uk-flex-1">Item 2</div>
<div class="uk-flex-1">Item 3</div>
</div>
<div class="uk-flex uk-flex-basis-25 uk-flex-grow-1">
<div>Flex item with basis 25% and grow 1</div>
</div>
<div class="uk-flex-grid uk-flex-grid-3">
<div>Grid Item 1</div>
<div>Grid Item 2</div>
<div>Grid Item 3</div>
<div>Grid Item 4</div>
<div>Grid Item 5</div>
<div>Grid Item 6</div>
</div>
<div class="uk-flex uk-flex-hover-lift">
<div>Hover to lift</div>
</div>
<div class="uk-flex uk-flex-animate uk-flex-slide-in">
<div>Animated flex container</div>
</div>Best Practices for Flex Components:
- Use flexbox for one-dimensional layouts (either row or column)
- Combine flex utilities with other UIKit utilities for complete layouts
- Always consider mobile-first responsive design
- Use semantic HTML elements with appropriate flex classes
- Test flex layouts across different screen sizes and browsers
- Use flex-grow, flex-shrink, and flex-basis appropriately
- Consider accessibility when reordering content with flex order
- Use CSS custom properties for consistent flex values
- Implement proper fallbacks for older browsers that don't support flexbox
- Use flex-wrap for responsive layouts that need to wrap items
- Consider using CSS Grid for two-dimensional layouts instead of complex flexbox
- Test with screen readers and keyboard navigation
- Use flexbox for centering content both vertically and horizontally
- Consider performance when using complex flexbox calculations
- Document custom flex utilities for team consistency
- Use flexbox gap property for consistent spacing (with fallbacks)
- Test print styles for flex layouts