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

Horizontal Dotnav

Default horizontal dot navigation

Vertical Dotnav

Vertical dot navigation for sidebars

Dotnav with Icons

Icon-based dot navigation

2. Dotnav Styles & Variations

Example Preview

Small Dotnav

Smaller dot size for compact layouts

Large Dotnav

Larger dots for better visibility

Square Dotnav

Square shaped navigation dots

Pill Dotnav

Pill-shaped navigation indicators

3. Dotnav with Content Navigation

Example Preview

Slideshow Navigation

  • Slide 1
    Slide 1: Introduction
  • Slide 2
    Slide 2: Features
  • Slide 3
    Slide 3: Benefits
Dotnav controlling a slideshow

Tab Navigation

Profile Settings

Manage your profile information and preferences.

Vertical dotnav as tab navigation

Step Progress Indicator

Step 2 of 4
Dotnav as multi-step progress indicator

4. Interactive Dotnav Features

Example Preview

Auto-playing Slideshow

  • Slide 1

    Auto-play every 3 seconds

  • Slide 2

    Click dots to navigate

  • Slide 3

    Hover to pause autoplay

Auto-playing with dot navigation controls

Filterable Gallery

Dotnav as filter controls for gallery

Rating System

0
out of 5 stars
Interactive rating system using dotnav

5. Responsive Dotnav Layouts

Example Preview

Responsive Dotnav Sizes

Small on mobile, medium on tablet, large on desktop

Mobile-Optimized Navigation

Horizontal on desktop, vertical on mobile

Pagination with Dotnav

Showing 1-10 of 50 items
Dotnav integrated with pagination controls

Dotnav Classes Reference

Core Classes

ClassDescriptionUsage
.uk-dotnavBase dot navigation class<ul class="uk-dotnav">
.uk-dotnav-verticalVertical dot navigationuk-dotnav uk-dotnav-vertical
.uk-activeActive dot item<li class="uk-active">
.uk-disabledDisabled dot item<li class="uk-disabled">

Size Classes

ClassDescriptionDot Size
.uk-dotnav-smallSmall dot size6px
(default)Default dot size10px
.uk-dotnav-mediumMedium dot size12px
.uk-dotnav-largeLarge dot size16px

Style Classes

ClassDescriptionEffect
.uk-dotnav-squareSquare shaped dotsborder-radius: 0
.uk-dotnav-pillPill shaped dotsborder-radius: 500px
.uk-dotnav-outlineOutline style dotsbackground: transparent
.uk-dotnav-filledFilled style dotsbackground: 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