Dotnav Component
Dotnav Component: Dotnav creates simple dot navigation for slideshows, carousels, and multi-step interfaces. It provides visual indicators for current position and allows users to navigate between items.
Live Examples
1. Basic Dot Navigation
Example Preview
2. Dotnav Styles & Variations
Example Preview
3. Dotnav with Content Navigation
Example Preview
Tab Navigation
Profile Settings
Manage your profile information and preferences.
Account Settings
Configure your account preferences and notification settings.
Billing Information
View and update your billing details and subscription.
Security Settings
Manage your password and security preferences.
4. Interactive Dotnav Features
Example Preview
5. Responsive Dotnav Layouts
Example Preview
Dotnav Classes Reference
Core Classes
| Class | Description | Usage |
|---|---|---|
.uk-dotnav | Base dot navigation class | <ul class="uk-dotnav"> |
.uk-dotnav-vertical | Vertical dot navigation | uk-dotnav uk-dotnav-vertical |
.uk-active | Active dot item | <li class="uk-active"> |
.uk-disabled | Disabled dot item | <li class="uk-disabled"> |
Size Classes
| Class | Description | Dot Size |
|---|---|---|
.uk-dotnav-small | Small dot size | 6px |
(default) | Default dot size | 10px |
.uk-dotnav-medium | Medium dot size | 12px |
.uk-dotnav-large | Large dot size | 16px |
Style Classes
| Class | Description | Effect |
|---|---|---|
.uk-dotnav-square | Square shaped dots | border-radius: 0 |
.uk-dotnav-pill | Pill shaped dots | border-radius: 500px |
.uk-dotnav-outline | Outline style dots | background: transparent |
.uk-dotnav-filled | Filled style dots | background: currentColor |
JavaScript API & Interactive Features
Dotnav JavaScript Methods & Events
// Dotnav component initialization
const dotnav = UIkit.dotnav(element, {
targets: '> *', // Target elements
active: 0, // Initial active index
vertical: false, // Vertical mode
delayActive: false // Delay active state
});
// Dotnav events
dotnavElement.addEventListener('beforeshow', function(event) {
console.log('Before showing item:', event.detail);
});
dotnavElement.addEventListener('show', function(event) {
console.log('Item shown:', event.detail);
const activeIndex = event.detail.index;
// Update related content
updateContent(activeIndex);
});
// Dynamic dotnav management
const dotnavManager = {
dotnavs: [],
initDotnav: function(dotnavId, options = {}) {
const dotnavElement = document.getElementById(dotnavId);
if (!dotnavElement) return null;
const dotnav = UIkit.dotnav(dotnavElement, options);
this.dotnavs.push({ id: dotnavId, element: dotnavElement, instance: dotnav });
return dotnav;
},
setActive: function(dotnavId, index) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return;
const items = dotnav.element.querySelectorAll('li');
items.forEach((item, i) => {
if (i === index) {
item.classList.add('uk-active');
} else {
item.classList.remove('uk-active');
}
});
// Trigger custom event
const event = new CustomEvent('dotnavChange', {
detail: { index: index, dotnavId: dotnavId }
});
dotnav.element.dispatchEvent(event);
},
getActiveIndex: function(dotnavId) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return -1;
const activeItem = dotnav.element.querySelector('li.uk-active');
if (!activeItem) return -1;
const items = Array.from(dotnav.element.querySelectorAll('li'));
return items.indexOf(activeItem);
},
addItem: function(dotnavId, content, isActive = false) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return;
const li = document.createElement('li');
if (isActive) {
li.classList.add('uk-active');
// Remove active from other items
dotnav.element.querySelectorAll('li').forEach(item => {
item.classList.remove('uk-active');
});
}
li.innerHTML = `<a href="#">${content}</a>`;
dotnav.element.appendChild(li);
// Add click handler
li.querySelector('a').addEventListener('click', function(e) {
e.preventDefault();
const index = Array.from(dotnav.element.querySelectorAll('li')).indexOf(li);
dotnavManager.setActive(dotnavId, index);
});
},
removeItem: function(dotnavId, index) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return;
const items = dotnav.element.querySelectorAll('li');
if (items[index]) {
const wasActive = items[index].classList.contains('uk-active');
items[index].remove();
// If active item was removed, activate first item
if (wasActive && items.length > 1) {
this.setActive(dotnavId, 0);
}
}
},
enableItem: function(dotnavId, index) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return;
const items = dotnav.element.querySelectorAll('li');
if (items[index]) {
items[index].classList.remove('uk-disabled');
items[index].querySelector('a').style.pointerEvents = 'auto';
}
},
disableItem: function(dotnavId, index) {
const dotnav = this.dotnavs.find(d => d.id === dotnavId);
if (!dotnav) return;
const items = dotnav.element.querySelectorAll('li');
if (items[index]) {
items[index].classList.add('uk-disabled');
items[index].querySelector('a').style.pointerEvents = 'none';
}
}
};
// Initialize dotnavs
dotnavManager.initDotnav('mainDotnav', { active: 0 });
dotnavManager.initDotnav('secondaryDotnav');
// Example usage
document.getElementById('nextBtn').addEventListener('click', function() {
const currentIndex = dotnavManager.getActiveIndex('mainDotnav');
const items = document.querySelectorAll('#mainDotnav li');
const nextIndex = (currentIndex + 1) % items.length;
dotnavManager.setActive('mainDotnav', nextIndex);
});
document.getElementById('prevBtn').addEventListener('click', function() {
const currentIndex = dotnavManager.getActiveIndex('mainDotnav');
const items = document.querySelectorAll('#mainDotnav li');
const prevIndex = (currentIndex - 1 + items.length) % items.length;
dotnavManager.setActive('mainDotnav', prevIndex);
});
// Dotnav with slideshow integration
const slideshowDotnav = {
slideshow: null,
dotnav: null,
init: function(slideshowId, dotnavId) {
this.slideshow = UIkit.slideshow(`#${slideshowId}`, {
autoplay: true,
autoplayInterval: 5000
});
this.dotnav = UIkit.dotnav(`#${dotnavId}`);
// Sync slideshow with dotnav
this.sync();
},
sync: function() {
const slideshowElement = document.getElementById(this.slideshow.$id);
const dotnavElement = document.getElementById(this.dotnav.$id);
// Update dotnav when slideshow changes
slideshowElement.addEventListener('itemshown', (event) => {
const index = event.detail.index;
const dotnavItems = dotnavElement.querySelectorAll('li');
dotnavItems.forEach((item, i) => {
if (i === index) {
item.classList.add('uk-active');
} else {
item.classList.remove('uk-active');
}
});
});
// Update slideshow when dotnav is clicked
dotnavElement.addEventListener('click', (event) => {
const target = event.target.closest('a');
if (!target) return;
event.preventDefault();
const li = target.parentElement;
const dotnavItems = Array.from(dotnavElement.querySelectorAll('li'));
const index = dotnavItems.indexOf(li);
if (index !== -1) {
this.slideshow.show(index);
}
});
},
play: function() {
this.slideshow.startAutoplay();
},
pause: function() {
this.slideshow.stopAutoplay();
},
next: function() {
this.slideshow.next();
},
previous: function() {
this.slideshow.previous();
}
};
// Initialize slideshow with dotnav
slideshowDotnav.init('productSlideshow', 'productDotnav');
// Interactive rating system
const ratingSystem = {
maxRating: 5,
currentRating: 0,
init: function(dotnavId) {
this.dotnav = document.getElementById(dotnavId);
if (!this.dotnav) return;
const dots = this.dotnav.querySelectorAll('li');
dots.forEach((dot, index) => {
const rating = index + 1;
dot.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
this.setRating(rating);
});
// Hover effects
dot.addEventListener('mouseenter', () => {
this.highlightUpTo(rating);
});
dot.addEventListener('mouseleave', () => {
this.highlightUpTo(this.currentRating);
});
});
// Initialize display
this.updateDisplay();
},
setRating: function(rating) {
this.currentRating = rating;
this.highlightUpTo(rating);
this.updateDisplay();
// Dispatch rating change event
const event = new CustomEvent('ratingChange', {
detail: { rating: rating }
});
this.dotnav.dispatchEvent(event);
},
highlightUpTo: function(rating) {
const dots = this.dotnav.querySelectorAll('li');
dots.forEach((dot, index) => {
if (index < rating) {
dot.classList.add('uk-active');
} else {
dot.classList.remove('uk-active');
}
});
},
updateDisplay: function() {
const display = document.getElementById('ratingValue');
if (display) {
display.textContent = this.currentRating;
}
},
reset: function() {
this.currentRating = 0;
this.highlightUpTo(0);
this.updateDisplay();
}
};
// Initialize rating system
ratingSystem.init('ratingDots');
// Filterable content with dotnav
const contentFilter = {
init: function(dotnavId, contentSelector) {
this.dotnav = document.getElementById(dotnavId);
this.content = document.querySelectorAll(contentSelector);
if (!this.dotnav) return;
const filterButtons = this.dotnav.querySelectorAll('a');
filterButtons.forEach(button => {
button.addEventListener('click', (e) => {
e.preventDefault();
// Update active state
filterButtons.forEach(btn => {
btn.parentElement.classList.remove('uk-active');
});
button.parentElement.classList.add('uk-active');
// Get filter value
const filterValue = button.getAttribute('data-filter') ||
button.textContent.toLowerCase();
// Filter content
this.filterContent(filterValue);
});
});
},
filterContent: function(filter) {
this.content.forEach(item => {
if (filter === 'all') {
item.style.display = '';
} else {
const itemCategories = item.getAttribute('data-category') ||
item.className.toLowerCase();
if (itemCategories.includes(filter)) {
item.style.display = '';
} else {
item.style.display = 'none';
}
}
});
// Dispatch filter event
const event = new CustomEvent('filterChange', {
detail: { filter: filter }
});
this.dotnav.dispatchEvent(event);
}
};
// Initialize content filter
contentFilter.init('filterDotnav', '.filterable-item');
// Progress tracker with dotnav
const progressTracker = {
steps: [],
currentStep: 0,
init: function(dotnavId, stepData) {
this.dotnav = document.getElementById(dotnavId);
this.steps = stepData;
if (!this.dotnav) return;
// Create dotnav items
this.steps.forEach((step, index) => {
const li = document.createElement('li');
if (index === 0) li.classList.add('uk-active');
li.innerHTML = `
<a href="#">
<span class="uk-badge">${index + 1}</span>
<div class="uk-text-small">${step.title}</div>
</a>
`;
li.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
this.goToStep(index);
});
this.dotnav.appendChild(li);
});
// Initialize first step
this.showStepContent(0);
},
goToStep: function(stepIndex) {
if (stepIndex < 0 || stepIndex >= this.steps.length) return;
// Update dotnav
const dots = this.dotnav.querySelectorAll('li');
dots.forEach((dot, index) => {
if (index <= stepIndex) {
dot.classList.add('uk-active');
} else {
dot.classList.remove('uk-active');
}
});
this.currentStep = stepIndex;
this.showStepContent(stepIndex);
// Update progress bar
const progress = ((stepIndex + 1) / this.steps.length * 100).toFixed(0);
const progressBar = document.getElementById('progressBar');
if (progressBar) {
progressBar.style.width = `${progress}%`;
progressBar.textContent = `${progress}%`;
}
},
showStepContent: function(stepIndex) {
const contentArea = document.getElementById('stepContent');
if (!contentArea) return;
const step = this.steps[stepIndex];
contentArea.innerHTML = `
<h3>${step.title}</h3>
<p>${step.description}</p>
${step.content || ''}
`;
},
next: function() {
if (this.currentStep < this.steps.length - 1) {
this.goToStep(this.currentStep + 1);
}
},
previous: function() {
if (this.currentStep > 0) {
this.goToStep(this.currentStep - 1);
}
},
complete: function() {
const dots = this.dotnav.querySelectorAll('li');
dots.forEach(dot => {
dot.classList.add('uk-active');
dot.classList.add('uk-success');
});
this.currentStep = this.steps.length - 1;
}
};
// Initialize progress tracker
const stepData = [
{ title: 'Cart', description: 'Review your cart items' },
{ title: 'Shipping', description: 'Enter shipping information' },
{ title: 'Payment', description: 'Provide payment details' },
{ title: 'Review', description: 'Review and confirm order' }
];
progressTracker.init('progressDotnav', stepData);Complete Real-World Examples
Product Image Gallery
<!-- Product Image Gallery with Dotnav -->
<div class="uk-card uk-card-default">
<div class="uk-card-header">
<h3 class="uk-card-title">iPhone 16 Pro - Space Black</h3>
<div class="uk-text-meta">$999 • 256GB • In Stock</div>
</div>
<div class="uk-card-body">
<!-- Main Image -->
<div class="uk-position-relative uk-visible-toggle" tabindex="-1" uk-slideshow="animation: fade">
<ul class="uk-slideshow-items uk-height-large">
<li>
<img src="iphone-front.jpg" alt="iPhone Front View" uk-cover>
<div class="uk-position-bottom-center uk-position-small">
<div class="uk-light">Front View</div>
</div>
</li>
<li>
<img src="iphone-back.jpg" alt="iPhone Back View" uk-cover>
<div class="uk-position-bottom-center uk-position-small">
<div class="uk-light">Back View</div>
</div>
</li>
<li>
<img src="iphone-side.jpg" alt="iPhone Side View" uk-cover>
<div class="uk-position-bottom-center uk-position-small">
<div class="uk-light">Side View</div>
</div>
</li>
<li>
<img src="iphone-camera.jpg" alt="iPhone Camera" uk-cover>
<div class="uk-position-bottom-center uk-position-small">
<div class="uk-light">Camera System</div>
</div>
</li>
<li>
<video autoplay loop muted uk-cover>
<source src="iphone-video.mp4" type="video/mp4">
</video>
<div class="uk-position-bottom-center uk-position-small">
<div class="uk-light">Video Demonstration</div>
</div>
</li>
</ul>
<!-- Navigation Arrows -->
<a class="uk-position-center-left uk-position-small uk-hidden-hover" href="#" uk-slidenav-previous uk-slideshow-item="previous"></a>
<a class="uk-position-center-right uk-position-small uk-hidden-hover" href="#" uk-slidenav-next uk-slideshow-item="next"></a>
<!-- Dotnav -->
<div class="uk-position-bottom-center uk-position-medium">
<ul class="uk-dotnav">
<li uk-slideshow-item="0"><a href="#">Front</a></li>
<li uk-slideshow-item="1"><a href="#">Back</a></li>
<li uk-slideshow-item="2"><a href="#">Side</a></li>
<li uk-slideshow-item="3"><a href="#">Camera</a></li>
<li uk-slideshow-item="4"><a href="#">Video</a></li>
</ul>
</div>
</div>
<!-- Thumbnail Navigation -->
<div class="uk-margin-top">
<ul class="uk-dotnav uk-flex-center">
<li class="uk-active">
<a href="#" onclick="showImage('iphone-front.jpg')">
<img src="iphone-front-thumb.jpg" width="60" height="60" alt="Front Thumbnail">
</a>
</li>
<li>
<a href="#" onclick="showImage('iphone-back.jpg')">
<img src="iphone-back-thumb.jpg" width="60" height="60" alt="Back Thumbnail">
</a>
</li>
<li>
<a href="#" onclick="showImage('iphone-side.jpg')">
<img src="iphone-side-thumb.jpg" width="60" height="60" alt="Side Thumbnail">
</a>
</li>
<li>
<a href="#" onclick="showImage('iphone-camera.jpg')">
<img src="iphone-camera-thumb.jpg" width="60" height="60" alt="Camera Thumbnail">
</a>
</li>
<li>
<a href="#" onclick="showVideo('iphone-video.mp4')">
<div class="uk-background-muted uk-flex uk-flex-center uk-flex-middle" style="width: 60px; height: 60px;">
<span uk-icon="icon: play; ratio: 1.5"></span>
</div>
</a>
</li>
</ul>
</div>
</div>
<div class="uk-card-footer">
<div class="uk-grid-small" uk-grid>
<div class="uk-width-expand">
<button class="uk-button uk-button-primary uk-width-1-1">
<span uk-icon="icon: cart" class="uk-margin-small-right"></span>
Add to Cart
</button>
</div>
<div class="uk-width-auto">
<button class="uk-button uk-button-default">
<span uk-icon="icon: heart"></span>
</button>
</div>
<div class="uk-width-auto">
<button class="uk-button uk-button-default">
<span uk-icon="icon: share"></span>
</button>
</div>
</div>
</div>
</div>
<script>
// Image gallery functionality
const productGallery = {
slideshow: null,
init: function() {
this.slideshow = UIkit.slideshow('.uk-slideshow', {
animation: 'fade',
autoplay: false
});
// Sync thumbnails with slideshow
this.syncThumbnails();
},
syncThumbnails: function() {
const thumbnails = document.querySelectorAll('.uk-dotnav img, .uk-dotnav .uk-background-muted');
const slideshowItems = document.querySelectorAll('.uk-slideshow-items li');
thumbnails.forEach((thumb, index) => {
thumb.addEventListener('click', (e) => {
e.preventDefault();
this.slideshow.show(index);
// Update thumbnail active state
document.querySelectorAll('.uk-dotnav li').forEach((li, i) => {
if (i === index) {
li.classList.add('uk-active');
} else {
li.classList.remove('uk-active');
}
});
});
});
// Update thumbnails when slideshow changes
document.querySelector('.uk-slideshow').addEventListener('itemshown', (e) => {
const index = e.detail.index;
document.querySelectorAll('.uk-dotnav li').forEach((li, i) => {
if (i === index) {
li.classList.add('uk-active');
} else {
li.classList.remove('uk-active');
}
});
});
},
showImage: function(imageSrc) {
// Implementation for direct image display
console.log('Showing image:', imageSrc);
},
showVideo: function(videoSrc) {
// Implementation for video display
console.log('Showing video:', videoSrc);
}
};
// Initialize gallery
productGallery.init();
</script>Onboarding Tutorial
<!-- Onboarding Tutorial with Dotnav -->
<div class="uk-card uk-card-primary uk-card-large uk-light">
<div class="uk-card-header">
<div class="uk-flex uk-flex-between uk-flex-middle">
<div>
<h3 class="uk-card-title uk-margin-remove-bottom">Welcome to Our Platform</h3>
<p class="uk-text-meta uk-margin-remove-top">Quick setup guide</p>
</div>
<div>
<button class="uk-button uk-button-text uk-light" id="skipTutorial">
Skip Tutorial
</button>
</div>
</div>
</div>
<div class="uk-card-body">
<!-- Tutorial Content -->
<div class="uk-position-relative" tabindex="-1" uk-slideshow="animation: slide">
<ul class="uk-slideshow-items">
<!-- Step 1 -->
<li>
<div class="uk-padding-large uk-text-center">
<div class="uk-margin-large-bottom">
<span class="uk-icon uk-icon-image" style="font-size: 4em;">🎯</span>
</div>
<h2 class="uk-heading-medium">Set Your Goals</h2>
<p class="uk-text-lead">Define what you want to achieve with our platform</p>
<div class="uk-margin-large-top">
<div class="uk-grid-small uk-child-width-1-2" uk-grid>
<div>
<button class="uk-button uk-button-default uk-width-1-1">
Personal Use
</button>
</div>
<div>
<button class="uk-button uk-button-default uk-width-1-1">
Business Use
</button>
</div>
</div>
</div>
</div>
</li>
<!-- Step 2 -->
<li>
<div class="uk-padding-large uk-text-center">
<div class="uk-margin-large-bottom">
<span class="uk-icon uk-icon-image" style="font-size: 4em;">⚙️</span>
</div>
<h2 class="uk-heading-medium">Customize Settings</h2>
<p class="uk-text-lead">Configure preferences to match your workflow</p>
<div class="uk-margin-large-top">
<div class="uk-form-stacked">
<div class="uk-margin">
<label class="uk-form-label">Notification Preferences</label>
<div class="uk-form-controls">
<select class="uk-select">
<option>All Notifications</option>
<option>Important Only</option>
<option>None</option>
</select>
</div>
</div>
<div class="uk-margin">
<label class="uk-form-label">Theme</label>
<div class="uk-form-controls">
<select class="uk-select">
<option>Light</option>
<option>Dark</option>
<option>Auto</option>
</select>
</div>
</div>
</div>
</div>
</div>
</li>
<!-- Step 3 -->
<li>
<div class="uk-padding-large uk-text-center">
<div class="uk-margin-large-bottom">
<span class="uk-icon uk-icon-image" style="font-size: 4em;">📊</span>
</div>
<h2 class="uk-heading-medium">Connect Data Sources</h2>
<p class="uk-text-lead">Link your accounts and import existing data</p>
<div class="uk-margin-large-top">
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
<div>
<button class="uk-button uk-button-default uk-width-1-1">
<span uk-icon="icon: google"></span>
Google
</button>
</div>
<div>
<button class="uk-button uk-button-default uk-width-1-1">
<span uk-icon="icon: facebook"></span>
Facebook
</button>
</div>
<div>
<button class="uk-button uk-button-default uk-width-1-1">
<span uk-icon="icon: dropbox"></span>
Dropbox
</button>
</div>
</div>
</div>
</div>
</li>
<!-- Step 4 -->
<li>
<div class="uk-padding-large uk-text-center">
<div class="uk-margin-large-bottom">
<span class="uk-icon uk-icon-image" style="font-size: 4em;">🚀</span>
</div>
<h2 class="uk-heading-medium">You're All Set!</h2>
<p class="uk-text-lead">Start exploring features and optimizing your workflow</p>
<div class="uk-margin-large-top">
<button class="uk-button uk-button-default uk-button-large" id="startExploring">
Start Exploring
</button>
</div>
<div class="uk-margin-top">
<a href="#" class="uk-link-text">Take a guided tour instead</a>
</div>
</div>
</li>
</ul>
<!-- Dotnav Controls -->
<div class="uk-position-bottom-center uk-position-medium">
<ul class="uk-dotnav">
<li uk-slideshow-item="0"><a href="#">1</a></li>
<li uk-slideshow-item="1"><a href="#">2</a></li>
<li uk-slideshow-item="2"><a href="#">3</a></li>
<li uk-slideshow-item="3"><a href="#">4</a></li>
</ul>
</div>
<!-- Navigation Buttons -->
<div class="uk-position-bottom-right uk-position-medium">
<div class="uk-button-group">
<button class="uk-button uk-button-default" id="prevStep">
<span uk-icon="icon: chevron-left"></span> Previous
</button>
<button class="uk-button uk-button-default" id="nextStep">
Next <span uk-icon="icon: chevron-right"></span>
</button>
</div>
</div>
</div>
<!-- Progress -->
<div class="uk-margin-top">
<div class="uk-grid-small uk-flex-middle" uk-grid>
<div class="uk-width-expand">
<div class="uk-progress">
<div class="uk-progress-bar" style="width: 25%;" id="tutorialProgress"></div>
</div>
</div>
<div class="uk-width-auto">
<span class="uk-text-small" id="progressText">Step 1 of 4</span>
</div>
</div>
</div>
</div>
</div>
<script>
// Tutorial functionality
const tutorial = {
slideshow: null,
currentStep: 0,
totalSteps: 4,
init: function() {
this.slideshow = UIkit.slideshow('.uk-slideshow', {
animation: 'slide',
autoplay: false
});
// Update progress when step changes
this.slideshow.$el.addEventListener('itemshown', (e) => {
this.currentStep = e.detail.index;
this.updateProgress();
});
// Navigation buttons
document.getElementById('prevStep').addEventListener('click', () => {
if (this.currentStep > 0) {
this.slideshow.prev();
}
});
document.getElementById('nextStep').addEventListener('click', () => {
if (this.currentStep < this.totalSteps - 1) {
this.slideshow.next();
} else {
this.completeTutorial();
}
});
// Skip tutorial
document.getElementById('skipTutorial').addEventListener('click', () => {
if (confirm('Skip the tutorial and go to dashboard?')) {
this.completeTutorial();
}
});
// Start exploring
document.getElementById('startExploring').addEventListener('click', () => {
this.completeTutorial();
});
// Initialize progress
this.updateProgress();
},
updateProgress: function() {
const progress = ((this.currentStep + 1) / this.totalSteps * 100).toFixed(0);
const progressBar = document.getElementById('tutorialProgress');
const progressText = document.getElementById('progressText');
if (progressBar) {
progressBar.style.width = `${progress}%`;
// Change color based on progress
if (progress < 50) {
progressBar.style.backgroundColor = '#f0506e'; // red
} else if (progress < 75) {
progressBar.style.backgroundColor = '#faa05a'; // orange
} else {
progressBar.style.backgroundColor = '#32d296'; // green
}
}
if (progressText) {
progressText.textContent = `Step ${this.currentStep + 1} of ${this.totalSteps}`;
}
// Update button text on last step
const nextButton = document.getElementById('nextStep');
if (this.currentStep === this.totalSteps - 1) {
nextButton.textContent = 'Complete';
} else {
nextButton.innerHTML = 'Next <span uk-icon="icon: chevron-right"></span>';
}
// Disable previous button on first step
const prevButton = document.getElementById('prevStep');
if (this.currentStep === 0) {
prevButton.disabled = true;
prevButton.classList.add('uk-disabled');
} else {
prevButton.disabled = false;
prevButton.classList.remove('uk-disabled');
}
},
completeTutorial: function() {
// Mark tutorial as completed
localStorage.setItem('tutorialCompleted', 'true');
// Show completion message
UIkit.notification({
message: 'Tutorial completed! Redirecting to dashboard...',
status: 'success',
pos: 'top-center',
timeout: 2000
});
// Redirect to dashboard
setTimeout(() => {
window.location.href = '/dashboard';
}, 2000);
},
saveStepData: function(step, data) {
// Save user inputs for each step
const tutorialData = JSON.parse(localStorage.getItem('tutorialData') || '{}');
tutorialData[step] = data;
localStorage.setItem('tutorialData', JSON.stringify(tutorialData));
}
};
// Initialize tutorial
tutorial.init();
// Save user inputs
document.querySelectorAll('select, input, button').forEach(element => {
element.addEventListener('change', function() {
const step = tutorial.currentStep;
const data = {
element: this.id || this.name,
value: this.value || this.textContent
};
tutorial.saveStepData(step, data);
});
});
</script>Custom Dotnav Styles
/* Custom Dotnav Styles */
/* Animated Dotnav */
.uk-dotnav-animated li a {
transition: all 0.3s ease;
}
.uk-dotnav-animated li.uk-active a {
transform: scale(1.5);
}
/* Gradient Dotnav */
.uk-dotnav-gradient li a {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
}
.uk-dotnav-gradient li.uk-active a {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
/* Glassmorphism Dotnav */
.uk-dotnav-glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
padding: 10px 20px;
}
.uk-dotnav-glass li a {
background: rgba(255, 255, 255, 0.3);
border: none;
}
.uk-dotnav-glass li.uk-active a {
background: rgba(255, 255, 255, 0.8);
}
/* Outline Dotnav */
.uk-dotnav-outline li a {
background: transparent;
border: 2px solid currentColor;
}
.uk-dotnav-outline li.uk-active a {
background: currentColor;
}
/* Pulse Animation */
.uk-dotnav-pulse li.uk-active a {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
/* Bounce Animation */
.uk-dotnav-bounce li a {
transition: transform 0.3s ease;
}
.uk-dotnav-bounce li a:hover {
transform: translateY(-5px);
}
/* Glow Effect */
.uk-dotnav-glow li.uk-active a {
box-shadow: 0 0 10px rgba(30, 135, 240, 0.7);
}
/* Custom Shapes */
.uk-dotnav-diamond li a {
transform: rotate(45deg);
}
.uk-dotnav-diamond li a span {
transform: rotate(-45deg);
display: block;
}
/* Color Variants */
.uk-dotnav-success li.uk-active a {
background-color: #32d296;
}
.uk-dotnav-warning li.uk-active a {
background-color: #faa05a;
}
.uk-dotnav-danger li.uk-active a {
background-color: #f0506e;
}
/* Size Variants */
.uk-dotnav-xs li a {
width: 4px;
height: 4px;
}
.uk-dotnav-xl li a {
width: 20px;
height: 20px;
}
.uk-dotnav-xxl li a {
width: 30px;
height: 30px;
}
/* Custom Spacing */
.uk-dotnav-spaced li {
margin: 0 10px;
}
.uk-dotnav-spaced-xl li {
margin: 0 20px;
}
/* Usage Examples */
<ul class="uk-dotnav uk-dotnav-animated">
<!-- Animated dotnav -->
</ul>
<ul class="uk-dotnav uk-dotnav-gradient">
<!-- Gradient dotnav -->
</ul>
<ul class="uk-dotnav uk-dotnav-glass">
<!-- Glassmorphism dotnav -->
</ul>
<ul class="uk-dotnav uk-dotnav-outline">
<!-- Outline dotnav -->
</ul>
<ul class="uk-dotnav uk-dotnav-pulse">
<!-- Pulse animation -->
</ul>
<ul class="uk-dotnav uk-dotnav-bounce">
<!-- Bounce animation -->
</ul>
<ul class="uk-dotnav uk-dotnav-glow">
<!-- Glow effect -->
</ul>
<ul class="uk-dotnav uk-dotnav-diamond">
<!-- Diamond shape -->
</ul>
<ul class="uk-dotnav uk-dotnav-success">
<!-- Success color -->
</ul>
<ul class="uk-dotnav uk-dotnav-xs">
<!-- Extra small -->
</ul>
<ul class="uk-dotnav uk-dotnav-spaced">
<!-- Spaced dots -->
</ul>
/* Responsive Dotnav */
@media (max-width: 640px) {
.uk-dotnav-responsive {
flex-wrap: wrap;
justify-content: center;
}
.uk-dotnav-responsive li {
margin: 5px;
}
}
/* Dotnav with Tooltips */
.uk-dotnav-tooltip li {
position: relative;
}
.uk-dotnav-tooltip li a:before {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.uk-dotnav-tooltip li a:hover:before {
opacity: 1;
}
/* Dotnav with Labels */
.uk-dotnav-labeled li {
display: flex;
flex-direction: column;
align-items: center;
}
.uk-dotnav-labeled .uk-dotnav-label {
font-size: 12px;
margin-top: 5px;
color: #666;
}
.uk-dotnav-labeled li.uk-active .uk-dotnav-label {
color: #1e87f0;
font-weight: bold;
}
/* Interactive Dotnav States */
.uk-dotnav-interactive li a {
cursor: pointer;
transition: all 0.3s ease;
}
.uk-dotnav-interactive li a:hover {
background-color: rgba(30, 135, 240, 0.3);
}
.uk-dotnav-interactive li.uk-active a {
background-color: #1e87f0;
cursor: default;
}
.uk-dotnav-interactive li.uk-disabled a {
background-color: #e5e5e5;
cursor: not-allowed;
}
/* Dotnav with Numbers */
.uk-dotnav-numbered li a {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border-radius: 50%;
font-size: 14px;
font-weight: bold;
text-decoration: none;
}
.uk-dotnav-numbered li.uk-active a {
background: #1e87f0;
color: white;
}
/* Custom Border Styles */
.uk-dotnav-border li a {
border: 2px solid transparent;
}
.uk-dotnav-border li.uk-active a {
border-color: #1e87f0;
}
.uk-dotnav-border-dashed li a {
border-style: dashed;
}
.uk-dotnav-border-dotted li a {
border-style: dotted;
}
/* Dotnav with Icons (Alternative) */
.uk-dotnav-icon li a {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
}
.uk-dotnav-icon li.uk-active a {
background: rgba(30, 135, 240, 0.1);
border-radius: 50%;
}
/* Loading State */
.uk-dotnav-loading li a {
position: relative;
overflow: hidden;
}
.uk-dotnav-loading li a:after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
animation: loading 1.5s infinite;
}
@keyframes loading {
to { left: 100%; }
}
/* Dotnav with Background */
.uk-dotnav-background {
background: #f8f8f8;
padding: 15px;
border-radius: 10px;
}
.uk-dotnav-background-dark {
background: #333;
padding: 15px;
border-radius: 10px;
}
.uk-dotnav-background-dark li a {
background: rgba(255,255,255,0.2);
}
.uk-dotnav-background-dark li.uk-active a {
background: white;
}
/* Custom Transitions */
.uk-dotnav-fade li {
opacity: 0.5;
transition: opacity 0.3s ease;
}
.uk-dotnav-fade li.uk-active {
opacity: 1;
}
.uk-dotnav-fade li:hover {
opacity: 0.8;
}
/* Dotnav with Shadow */
.uk-dotnav-shadow li a {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.uk-dotnav-shadow li.uk-active a {
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
/* Hover Effects */
.uk-dotnav-hover-scale li a {
transition: transform 0.3s ease;
}
.uk-dotnav-hover-scale li a:hover {
transform: scale(1.2);
}
.uk-dotnav-hover-rotate li a {
transition: transform 0.3s ease;
}
.uk-dotnav-hover-rotate li a:hover {
transform: rotate(45deg);
}
/* Accessibility Focus Styles */
.uk-dotnav-accessible li a:focus {
outline: 2px solid #1e87f0;
outline-offset: 2px;
}
/* Print Styles */
@media print {
.uk-dotnav {
display: none;
}
}Best Practices for Dotnav Components:
- Always provide clear visual feedback for the active state
- Ensure dotnav is accessible via keyboard navigation
- Use appropriate dot sizes for touch targets on mobile devices
- Provide aria-labels for screen readers when dots don't have text
- Maintain consistent spacing between dots
- Use color contrast that meets accessibility standards
- Implement responsive behavior for different screen sizes
- Consider using tooltips for dot labels on icon-only dotnavs
- Provide clear navigation instructions for first-time users
- Test dotnav functionality across different devices and browsers
- Use semantic HTML structure for better SEO and accessibility
- Implement smooth transitions between states
- Consider implementing swipe gestures for mobile touch navigation
- Provide fallback navigation for JavaScript-disabled environments
- Use appropriate cursor styles to indicate interactivity
- Consider implementing infinite scroll or pagination for large content sets