Help Center / Widget SDK

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' });
    }
  }
});

UserJot

Last updated on August 13, 2025.