@suggesto/nuxt
v1.0.5
Published
Nuxt 3 & 4 module for Suggesto feedback widget integration
Maintainers
Readme
@suggesto/nuxt
Nuxt 3 module for Suggesto feedback widget integration. Provides zero-configuration setup with automatic widget loading and optimal performance.
Installation
npm install @suggesto/nuxtQuick Setup
Add the module to your nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'@suggesto/nuxt'
],
suggesto: {
boardId: 'your-board-id', // Required
baseUrl: 'https://suggesto.io' // Optional
}
});That's it! The widget will be automatically loaded on all pages.
Usage
Automatic Widget Loading
With the module configured, the widget loads automatically on all pages without any additional code:
<template>
<div>
<h1>My Nuxt App</h1>
<!-- Widget loads automatically -->
</div>
</template>Programmatic Control
Access the widget programmatically using the provided composable:
<template>
<div>
<h1>My App</h1>
<button @click="openFeedback" :disabled="isLoading">
{{ isLoading ? 'Loading...' : 'Give Feedback' }}
</button>
<div v-if="error" class="error">
Error loading widget: {{ error }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
// Reactive state
const isLoading = ref(true);
const error = ref(null);
let openModal = ref(() => {});
const openFeedback = () => {
openModal.value();
};
// Client-side only initialization
onMounted(() => {
// Access the suggesto composable through Nuxt app (client-side only)
const { $suggesto, $suggestoConfig } = useNuxtApp();
if ($suggesto && $suggestoConfig) {
const suggestoInstance = $suggesto($suggestoConfig);
// Use the global reactive references directly
isLoading.value = suggestoInstance.isLoading.value;
error.value = suggestoInstance.error.value;
openModal.value = suggestoInstance.openModal;
// Watch for changes in the global state
watch(suggestoInstance.isLoading, (newValue) => {
isLoading.value = newValue;
}, { immediate: true });
watch(suggestoInstance.error, (newValue) => {
error.value = newValue;
}, { immediate: true });
// Listen for events
suggestoInstance.on('ready', (data) => {
console.log('Widget ready:', data);
});
suggestoInstance.on('feedbackSubmitted', (data) => {
console.log('Feedback submitted:', data);
// Track analytics, show toast, etc.
});
suggestoInstance.on('error', (errorData) => {
console.error('Widget error:', errorData);
});
}
});
</script>Custom Configuration Per Page
Override default configuration for specific pages:
<template>
<div>
<h1>Special Page</h1>
<!-- Custom widget instance -->
</div>
</template>
<script setup>
// Use custom config for this page
const { $suggesto } = useNuxtApp();
const { openModal, on } = $suggesto({
boardId: 'special-board-id',
baseUrl: 'https://custom.domain.com'
});
on('ready', (data) => {
console.log('Custom widget ready:', data);
});
</script>Configuration
Module Options
Configure the module in your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@suggesto/nuxt'],
suggesto: {
// Required: Your feedback board UUID
boardId: 'your-board-id',
// Optional: Custom server URL (default: 'https://suggesto.io')
baseUrl: 'https://your-custom-domain.com'
}
});Environment Variables
Use environment variables for different environments:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@suggesto/nuxt'],
suggesto: {
boardId: process.env.NUXT_SUGGESTO_BOARD_ID,
baseUrl: process.env.NUXT_SUGGESTO_BASE_URL || 'https://suggesto.io'
}
});# .env
NUXT_SUGGESTO_BOARD_ID=your-production-board-id
NUXT_SUGGESTO_BASE_URL=https://suggesto.ioRuntime Config
Access configuration at runtime:
<script setup>
const config = useRuntimeConfig();
console.log('Board ID:', config.public.suggesto.boardId);
</script>API Reference
Composable: $suggesto(config)
The module provides the same composable from @suggesto/vue through the Nuxt app context.
Parameters
config?: SuggestoConfig- Optional config override
Returns
{
isLoading: Ref<boolean>; // Widget loading state
error: Ref<string | null>; // Error message if loading failed
openModal: () => void; // Open feedback modal
closeModal: () => void; // Close feedback modal
on: (event, callback) => void; // Register event listener
}Global Properties
The module adds these properties to the Nuxt app:
$suggesto- The useSuggesto composable from @suggesto/vue$suggestoConfig- The module configuration
Events
The module supports all events from @suggesto/core:
ready
{
boardId: string;
boardSlug: string;
position: string;
theme: string;
color: string;
widget: any;
}feedbackSubmitted
{
boardId: string;
category: string;
title: string;
body: string;
feedbackId: string;
success: boolean;
}error
{
type: string;
error: string;
boardId: string;
context: string;
}Advanced Usage
Conditional Loading
Load the widget only on specific pages:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@suggesto/nuxt'],
suggesto: {
boardId: 'your-board-id'
}
});<!-- pages/contact.vue -->
<template>
<div>
<h1>Contact Us</h1>
<!-- Widget only loads on this page -->
</div>
</template>
<script setup>
// Only initialize widget on this specific page
const { $suggesto, $suggestoConfig } = useNuxtApp();
onMounted(() => {
if (process.client) {
$suggesto($suggestoConfig);
}
});
</script>Multiple Widgets
Use different widgets for different sections:
<script setup>
const { $suggesto } = useNuxtApp();
// Main product feedback
const mainWidget = $suggesto({
boardId: 'main-product-board-id'
});
// Beta feature feedback
const betaWidget = $suggesto({
boardId: 'beta-features-board-id'
});
</script>Analytics Integration
Track widget events with your analytics:
<script setup>
const { $suggesto, $suggestoConfig } = useNuxtApp();
const { on } = $suggesto($suggestoConfig);
on('feedbackSubmitted', (data) => {
// Google Analytics
gtag('event', 'feedback_submitted', {
category: data.category,
board_id: data.boardId
});
// Plausible
plausible('Feedback Submitted', {
props: {
category: data.category,
board: data.boardId
}
});
});
</script>Performance
Server-Side Rendering
The widget is client-side only and won't affect your SSR performance. It loads after hydration is complete.
Singleton Pattern
Version 1.0.4+ implements a singleton pattern to prevent widget instance conflicts:
- Auto-loading creates a single global widget instance
- Manual composable usage reuses the same instance
- Events and state are shared across the application
- No duplicate widget loading or conflicts
Code Splitting
The widget script is loaded dynamically, keeping your main bundle size minimal.
Caching
Widget configurations are cached on the server for optimal performance.
TypeScript Support
Full TypeScript support with auto-completion:
// types/suggesto.d.ts
import type { SuggestoEvents } from '@suggesto/nuxt';
// Extend Nuxt app type
declare module '#app' {
interface NuxtApp {
$suggesto: typeof import('@suggesto/vue').useSuggesto;
$suggestoConfig: import('@suggesto/core').SuggestoConfig;
}
}Troubleshooting
Module not loading
- Ensure you've added the module to
nuxt.config.ts - Check that
boardIdis correctly configured - Verify your domain is whitelisted in Suggesto dashboard
Widget not appearing
The widget loads client-side only. Check browser console for errors and ensure JavaScript is enabled.
Widget button stuck on "Loading..."
Fixed in v1.0.4: The singleton pattern ensures proper state management.
If you're still having issues:
- Ensure you're using v1.0.4 or later
- Check that you're using the updated programmatic control pattern shown above
- Events should now register correctly in the console
"$suggesto is not a function" error
This occurs when trying to access the composable during SSR. Always wrap composable usage in onMounted():
<script setup>
onMounted(() => {
const { $suggesto } = useNuxtApp();
// Use composable here
});
</script>Auto-loading conflicts with manual control
Fixed in v1.0.4: The singleton pattern prevents conflicts between auto-loading and manual usage.
Events not firing
Events are automatically handled by the singleton instance. All events will be properly fired and can be listened to via the composable.
TypeScript errors
Install the required types:
npm install @types/nodeMake sure your nuxt.config.ts has proper TypeScript configuration.
Migration
From Vue Plugin
If migrating from the Vue plugin:
- import { SuggestoWidget } from '@suggesto/vue';
+ // Remove manual import, widget loads automatically
// nuxt.config.ts
export default defineNuxtConfig({
+ modules: ['@suggesto/nuxt'],
+ suggesto: {
+ boardId: 'your-board-id'
+ }
});From Script Tag
If migrating from script tag installation:
// Remove from app.html or layouts
- <script src="https://suggesto.io/widget/your-board-id"></script>
// Add to nuxt.config.ts
+ modules: ['@suggesto/nuxt'],
+ suggesto: {
+ boardId: 'your-board-id'
+ }Examples
Check the playground directory for a complete working example.
License
MIT
