Advanced

Custom widget integrations

Integrate the UserJot widget with your own UI components and workflows.

Custom trigger buttons

Replace the default floating button with your own design.

Basic custom button

// Initialize with custom trigger
window.uj.init('YOUR_PROJECT_ID', {
  widget: true,
  trigger: 'custom' // Hides default button
});

// Open widget with your button
document.getElementById('feedback-btn').onclick = () => {
  window.uj.showWidget();
};

Multiple trigger points

Add feedback triggers throughout your application:

// Header feedback button
document.querySelector('.header-feedback').onclick = () => {
  window.uj.showWidget({ section: 'feedback' });
};

// Footer roadmap link
document.querySelector('.footer-roadmap').onclick = () => {
  window.uj.showWidget({ section: 'roadmap' });
};

// Help menu updates option
document.querySelector('.help-updates').onclick = () => {
  window.uj.showWidget({ section: 'updates' });
};

Conditional display

Show the widget based on user actions or application state.

Show after user action

// Show after task completion
function onTaskComplete() {
  setTimeout(() => {
    window.uj.showWidget({ section: 'feedback' });
  }, 2000);
}

// Show on error
window.addEventListener('error', (event) => {
  if (event.error?.userFacing) {
    window.uj.showWidget({ section: 'feedback' });
  }
});

Show based on user segment

// Show for specific user types
if (user.plan === 'premium' && user.daysActive > 30) {
  window.uj.setWidgetEnabled(true);
} else {
  window.uj.setWidgetEnabled(false);
}

State synchronization

Keep your app in sync with widget state.

Track widget visibility

// Monitor widget state changes
let previousState = { isOpen: false, section: null };

setInterval(() => {
  const currentState = window.uj.getWidgetState();

  if (currentState.isOpen !== previousState.isOpen) {
    // Widget opened or closed
    analytics.track('Widget Toggled', {
      isOpen: currentState.isOpen,
      section: currentState.section
    });
  }

  previousState = currentState;
}, 1000);

Coordinate with modals

// Close widget when opening modal
function openModal() {
  window.uj.hideWidget();
  // Show your modal
}

// Check widget before showing modal
function showModal() {
  const state = window.uj.getWidgetState();
  if (state.isOpen) {
    window.uj.hideWidget();
    setTimeout(showModal, 300); // Wait for animation
  } else {
    // Show modal
  }
}

Framework integrations

React

// Custom hook
function useUserJot() {
  const [widgetState, setWidgetState] = useState({
    isOpen: false,
    section: null
  });

  useEffect(() => {
    const interval = setInterval(() => {
      setWidgetState(window.uj.getWidgetState());
    }, 500);

    return () => clearInterval(interval);
  }, []);

  const showWidget = (section) => {
    window.uj.showWidget({ section });
  };

  const hideWidget = () => {
    window.uj.hideWidget();
  };

  return { widgetState, showWidget, hideWidget };
}

// Component usage
function FeedbackButton() {
  const { widgetState, showWidget, hideWidget } = useUserJot();

  return (
    <button
      onClick={() =>
        widgetState.isOpen ? hideWidget() : showWidget('feedback')
      }
    >
      {widgetState.isOpen ? 'Close' : 'Feedback'}
    </button>
  );
}

Vue

<template>
  <button @click="toggleWidget">
    {{ widgetOpen ? 'Close' : 'Send Feedback' }}
  </button>
</template>

<script>
export default {
  data() {
    return {
      widgetOpen: false
    };
  },
  methods: {
    toggleWidget() {
      if (this.widgetOpen) {
        window.uj.hideWidget();
      } else {
        window.uj.showWidget({ section: 'feedback' });
      }
      this.widgetOpen = !this.widgetOpen;
    }
  },
  mounted() {
    // Check state periodically
    setInterval(() => {
      const state = window.uj.getWidgetState();
      this.widgetOpen = state.isOpen;
    }, 500);
  }
};
</script>

Angular

@Component({
  selector: 'app-feedback',
  template: `
    <button (click)="toggleWidget()">
      {{ getButtonText() }}
    </button>
  `
})
export class FeedbackComponent implements OnInit {
  widgetState = { isOpen: false, section: null };

  ngOnInit() {
    // Poll widget state
    interval(500).subscribe(() => {
      this.widgetState = (window as any).uj.getWidgetState();
    });
  }

  toggleWidget() {
    if (this.widgetState.isOpen) {
      (window as any).uj.hideWidget();
    } else {
      (window as any).uj.showWidget({ section: 'feedback' });
    }
  }

  getButtonText() {
    return this.widgetState.isOpen ? 'Close' : 'Feedback';
  }
}

Analytics integration

Track widget interactions for insights.

// Track widget events
function trackWidgetEvent(action, data = {}) {
  // Your analytics tool
  analytics.track(`Widget ${action}`, {
    ...data,
    timestamp: Date.now()
  });
}

// Track opens
document.querySelector('.feedback-trigger').onclick = () => {
  trackWidgetEvent('Opened', {
    trigger: 'custom_button',
    section: 'feedback'
  });
  window.uj.showWidget({ section: 'feedback' });
};

// Track state changes
let lastState = { isOpen: false };
setInterval(() => {
  const state = window.uj.getWidgetState();

  if (state.isOpen && !lastState.isOpen) {
    trackWidgetEvent('Opened', {
      section: state.section
    });
  } else if (!state.isOpen && lastState.isOpen) {
    trackWidgetEvent('Closed', {
      lastSection: lastState.section
    });
  }

  lastState = state;
}, 1000);

Keyboard shortcuts

Add keyboard shortcuts to open the widget.

document.addEventListener('keydown', (e) => {
  // Cmd/Ctrl + K to open feedback
  if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
    e.preventDefault();
    const state = window.uj.getWidgetState();

    if (state.isOpen) {
      window.uj.hideWidget();
    } else {
      window.uj.showWidget({ section: 'feedback' });
    }
  }
});

Hey! How can I help you navigate the docs today?