Customization

Advanced customization options for the Notedis feedback widget.

Overview

Beyond basic configuration, you can deeply customize the widget's appearance, behavior, and integration with your site.


Custom Styling with CSS

Targeting Widget Elements

The widget uses specific IDs and classes you can target with CSS:

/* Feedback button */
#notedis-feedback-button {
  /* Your custom styles */
}

/* Modal overlay */
#notedis-modal-overlay {
  /* Your custom styles */
}

/* Modal container */
#notedis-modal {
  /* Your custom styles */
}

Change Button Size

#notedis-feedback-button {
  padding: 16px 24px !important;
  font-size: 18px !important;
}

Change Button Shape

/* Circular button */
#notedis-feedback-button {
  border-radius: 50% !important;
  width: 60px !important;
  height: 60px !important;
  padding: 0 !important;
}

/* Square button */
#notedis-feedback-button {
  border-radius: 0 !important;
}

/* Pill shape */
#notedis-feedback-button {
  border-radius: 50px !important;
}

Custom Button Shadow

#notedis-feedback-button {
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3) !important;
}

/* Remove shadow */
#notedis-feedback-button {
  box-shadow: none !important;
}

Adjust Z-Index

If the widget is appearing behind other elements:

#notedis-feedback-button {
  z-index: 999999 !important;
}

#notedis-modal-overlay {
  z-index: 999998 !important;
}

#notedis-modal {
  z-index: 999999 !important;
}

Responsive Button Size

/* Default size */
#notedis-feedback-button {
  padding: 12px 20px !important;
  font-size: 14px !important;
}

/* Smaller on mobile */
@media (max-width: 768px) {
  #notedis-feedback-button {
    padding: 10px 16px !important;
    font-size: 12px !important;
  }
}

Custom Position with CSS

Override default position:

/* Centered at bottom */
#notedis-feedback-button {
  left: 50% !important;
  right: auto !important;
  transform: translateX(-50%) !important;
  bottom: 20px !important;
}

/* Top center */
#notedis-feedback-button {
  left: 50% !important;
  right: auto !important;
  transform: translateX(-50%) !important;
  top: 20px !important;
  bottom: auto !important;
}

Custom Animations

/* Pulse animation */
@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
}

#notedis-feedback-button {
  animation: pulse 2s infinite !important;
}

/* Slide in from right */
@keyframes slideIn {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

#notedis-feedback-button {
  animation: slideIn 0.5s ease-out !important;
}

Dark Theme Customization

If your site has a dark mode:

/* Dark mode widget button */
@media (prefers-color-scheme: dark) {
  #notedis-feedback-button {
    background-color: #1f2937 !important;
    color: #f9fafb !important;
    border: 1px solid #374151 !important;
  }

  #notedis-feedback-button:hover {
    background-color: #374151 !important;
  }
}

Custom Trigger Button

Hide the default button and use your own custom trigger.

Basic Custom Trigger

<!-- Your custom button -->
<button id="my-feedback-btn" class="my-custom-class">
  Give Feedback
</button>

<script>
  window.notedisConfig = {
    siteKey: 'your-site-key',
    apiUrl: 'https://notedis.com',
    hideButton: true // Hide default button
  };
</script>
<script src="https://notedis.com/js/widget.js" defer></script>

<script>
  // Wait for widget to load
  document.addEventListener('DOMContentLoaded', function() {
    document.getElementById('my-feedback-btn').addEventListener('click', function() {
      if (window.notedisWidget) {
        window.notedisWidget.open();
      }
    });
  });
</script>

Multiple Trigger Buttons

<!-- Multiple buttons on different pages -->
<button class="feedback-trigger">Report Bug</button>
<button class="feedback-trigger">Send Feedback</button>
<button class="feedback-trigger">Contact Us</button>

<script>
  window.notedisConfig = {
    siteKey: 'your-site-key',
    apiUrl: 'https://notedis.com',
    hideButton: true
  };
</script>
<script src="https://notedis.com/js/widget.js" defer></script>

<script>
  document.addEventListener('DOMContentLoaded', function() {
    // Attach to all buttons with class
    document.querySelectorAll('.feedback-trigger').forEach(function(button) {
      button.addEventListener('click', function() {
        if (window.notedisWidget) {
          window.notedisWidget.open();
        }
      });
    });
  });
</script>

Custom Trigger with Icon

<!-- Font Awesome icon -->
<button id="feedback-icon" style="position: fixed; bottom: 20px; right: 20px; background: #3B82F6; color: white; border: none; border-radius: 50%; width: 60px; height: 60px; cursor: pointer; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
  <i class="fas fa-comment-alt fa-lg"></i>
</button>

<script>
  document.addEventListener('DOMContentLoaded', function() {
    document.getElementById('feedback-icon').addEventListener('click', function() {
      window.notedisWidget?.open();
    });
  });
</script>

Trigger from Navigation Menu

<!-- In your site navigation -->
<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
  <a href="#" id="feedback-link">Feedback</a>
</nav>

<script>
  document.getElementById('feedback-link').addEventListener('click', function(e) {
    e.preventDefault();
    window.notedisWidget?.open();
  });
</script>

Callback Functions

Execute custom code when widget events occur.

Track When Widget Opens

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onOpen: function() {
    console.log('Feedback widget opened');

    // Track with Google Analytics
    if (window.gtag) {
      gtag('event', 'feedback_opened', {
        event_category: 'engagement'
      });
    }

    // Track with Mixpanel
    if (window.mixpanel) {
      mixpanel.track('Feedback Widget Opened');
    }

    // Show a tooltip or help text
    document.getElementById('help-text').style.display = 'block';
  }
};

Track When Feedback Is Submitted

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onSubmit: function(feedback) {
    console.log('Feedback submitted:', feedback);

    // Show thank you message
    alert('Thank you for your feedback!');

    // Track with analytics
    if (window.gtag) {
      gtag('event', 'feedback_submitted', {
        event_category: 'engagement',
        feedback_category: feedback.category,
        feedback_priority: feedback.priority
      });
    }

    // Redirect to thank you page
    // window.location.href = '/thank-you';

    // Or show a custom modal
    document.getElementById('thank-you-modal').classList.add('show');
  }
};

Track When Widget Closes

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onClose: function() {
    console.log('Feedback widget closed');

    // Hide help text
    document.getElementById('help-text').style.display = 'none';

    // Track abandonment
    if (window.gtag) {
      gtag('event', 'feedback_closed', {
        event_category: 'engagement'
      });
    }
  }
};

Combined Example

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onOpen: function() {
    // Pause video if playing
    const video = document.querySelector('video');
    if (video && !video.paused) {
      video.pause();
      window.videoPausedByWidget = true;
    }

    // Track analytics
    gtag?.('event', 'feedback_opened');
  },

  onClose: function() {
    // Resume video if we paused it
    if (window.videoPausedByWidget) {
      const video = document.querySelector('video');
      video?.play();
      window.videoPausedByWidget = false;
    }
  },

  onSubmit: function(feedback) {
    // Show thank you message
    const toast = document.createElement('div');
    toast.textContent = 'Thank you for your feedback!';
    toast.style.cssText = 'position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #10b981; color: white; padding: 12px 24px; border-radius: 8px; z-index: 999999;';
    document.body.appendChild(toast);

    setTimeout(() => toast.remove(), 3000);

    // Track detailed analytics
    gtag?.('event', 'feedback_submitted', {
      category: feedback.category,
      priority: feedback.priority,
      has_screenshot: !!feedback.screenshot,
      page_url: window.location.href
    });
  }
};

Programmatic Control

Control the widget via JavaScript.

Open Widget Programmatically

// From anywhere in your code
if (window.notedisWidget) {
  window.notedisWidget.open();
}

Close Widget Programmatically

if (window.notedisWidget) {
  window.notedisWidget.close();
}

Trigger After User Action

// Open after user spends 30 seconds on page
setTimeout(() => {
  window.notedisWidget?.open();
}, 30000);

// Open when user scrolls to bottom
window.addEventListener('scroll', function() {
  const scrolledToBottom = (window.innerHeight + window.scrollY) >= document.body.offsetHeight;

  if (scrolledToBottom) {
    window.notedisWidget?.open();
  }
});

// Open on exit intent
document.addEventListener('mouseout', function(e) {
  if (e.clientY < 0) {
    window.notedisWidget?.open();
  }
});

Conditional Display

Show widget only in specific conditions.

Show Only for Logged-In Users

// Check if user is logged in
const isLoggedIn = document.body.classList.contains('logged-in');
// Or check a cookie, session storage, etc.

if (isLoggedIn) {
  window.notedisConfig = {
    siteKey: 'your-site-key',
    apiUrl: 'https://notedis.com'
  };

  const script = document.createElement('script');
  script.src = 'https://notedis.com/js/widget.js';
  script.defer = true;
  document.body.appendChild(script);
}

Hide on Specific Pages

// Don't show on checkout or payment pages
const hideOnPages = ['/checkout', '/payment', '/cart'];
const currentPath = window.location.pathname;
const shouldHide = hideOnPages.some(page => currentPath.includes(page));

if (!shouldHide) {
  window.notedisConfig = {
    siteKey: 'your-site-key',
    apiUrl: 'https://notedis.com'
  };

  const script = document.createElement('script');
  script.src = 'https://notedis.com/js/widget.js';
  script.defer = true;
  document.body.appendChild(script);
}

Show Only on Staging/Dev

// Only show on non-production environments
const isProduction = window.location.hostname === 'mysite.com';

if (!isProduction) {
  window.notedisConfig = {
    siteKey: 'your-dev-site-key',
    apiUrl: 'https://notedis.com',
    color: '#ef4444', // Red for dev
    buttonText: '🚧 Dev Feedback'
  };

  const script = document.createElement('script');
  script.src = 'https://notedis.com/js/widget.js';
  script.defer = true;
  document.body.appendChild(script);
}

Show Based on User Role

// Get user role from your app
const userRole = window.appData?.userRole; // 'admin', 'editor', 'subscriber', etc.

if (['admin', 'editor'].includes(userRole)) {
  window.notedisConfig = {
    siteKey: 'your-site-key',
    apiUrl: 'https://notedis.com',
    buttonText: 'Staff Feedback'
  };

  const script = document.createElement('script');
  script.src = 'https://notedis.com/js/widget.js';
  script.defer = true;
  document.body.appendChild(script);
}

Integration Examples

Google Analytics Integration

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onOpen: function() {
    gtag('event', 'feedback_widget_opened', {
      event_category: 'Engagement',
      event_label: window.location.pathname
    });
  },

  onSubmit: function(feedback) {
    gtag('event', 'feedback_submitted', {
      event_category: 'Engagement',
      event_label: feedback.category,
      value: feedback.priority === 'high' ? 3 : feedback.priority === 'medium' ? 2 : 1
    });
  }
};

Mixpanel Integration

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onSubmit: function(feedback) {
    mixpanel.track('Feedback Submitted', {
      category: feedback.category,
      priority: feedback.priority,
      page: window.location.pathname,
      has_screenshot: !!feedback.screenshot
    });
  }
};

Intercom Integration

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onSubmit: function(feedback) {
    // Log feedback submission in Intercom
    if (window.Intercom) {
      Intercom('trackEvent', 'feedback-submitted', {
        category: feedback.category,
        priority: feedback.priority
      });
    }
  }
};

Advanced Customization

Detect Widget Load

// Check when widget is fully loaded
const checkWidgetLoaded = setInterval(() => {
  if (window.notedisWidget) {
    console.log('Widget loaded and ready');
    clearInterval(checkWidgetLoaded);

    // Now you can safely use widget methods
    // window.notedisWidget.open();
  }
}, 100);

Custom Loading Indicator

// Show loading indicator while widget loads
const loadingIndicator = document.createElement('div');
loadingIndicator.id = 'widget-loading';
loadingIndicator.textContent = 'Loading feedback widget...';
document.body.appendChild(loadingIndicator);

const checkLoaded = setInterval(() => {
  if (window.notedisWidget) {
    loadingIndicator.remove();
    clearInterval(checkLoaded);
  }
}, 100);

Pre-fill Feedback Data

While the widget doesn't support pre-filling user input directly, you can use callbacks to capture additional context:

window.notedisConfig = {
  siteKey: 'your-site-key',
  apiUrl: 'https://notedis.com',

  onSubmit: function(feedback) {
    // Send additional context to your backend
    fetch('/api/feedback-context', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        feedbackId: feedback.id,
        userId: window.currentUser?.id,
        userPlan: window.currentUser?.plan,
        pageLoadTime: performance.now(),
        browserMemory: performance.memory?.usedJSHeapSize
      })
    });
  }
};

Accessibility Customization

Keyboard Shortcuts

// Open widget with Ctrl+K or Cmd+K
document.addEventListener('keydown', function(e) {
  if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
    e.preventDefault();
    window.notedisWidget?.open();
  }
});

High Contrast Mode

/* For users with high contrast preferences */
@media (prefers-contrast: high) {
  #notedis-feedback-button {
    border: 2px solid currentColor !important;
    font-weight: bold !important;
  }
}

Reduced Motion

/* Respect user's motion preferences */
@media (prefers-reduced-motion: reduce) {
  #notedis-feedback-button {
    animation: none !important;
    transition: none !important;
  }
}

Next Steps