npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

solucx-survey-widget

v0.0.18

Published

A customizable survey widget component built with Vue.js that can be integrated into various web frameworks. This widget allows you to embed SoluCX surveys directly into your applications with support for different display modes and comprehensive event ha

Readme

SoluCX Survey Widget

A customizable survey widget component built with Vue.js that can be integrated into various web frameworks. This widget allows you to embed SoluCX surveys directly into your applications with support for different display modes and comprehensive event handling.

Features

  • 🎯 Multiple widget types: inline, modal, bottom bar, bottom box (left/right)
  • 📱 Responsive design with customizable dimensions
  • 🔒 Security-focused with domain validation and data sanitization
  • 📊 Built-in analytics and user behavior tracking
  • ⚡ Framework agnostic - works with Vue, React, Angular, and more
  • 🎨 Customizable styling and positioning
  • 📡 Real-time event handling and callbacks

Installation

npm install solucx-survey-widget

Configuration

The widget requires the following props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | soluCxKey | string | ✅ | Your SoluCX survey key | | widgetType | WidgetType | ✅ | Display mode: 'inline', 'modal', 'bottomBar', 'bottomBox', 'bottomBoxLeft' | | widgetData | WidgetData \| string | ✅ | Survey data (object or JSON string) | | widgetOptions | WidgetOptions \| string | ❌ | Configuration options |

Widget Data Structure

interface WidgetData {
  customer_id?: string
  email?: string
  name?: string
  phone?: string
  document?: string
  transaction_id?: string
  // ... other custom fields
}

Widget Options

interface WidgetOptions {
  width?: number        // Widget width in pixels
  height?: number       // Widget height in pixels
  retry?: {
    attempts?: number   // Max retry attempts (default: 5)
    interval?: number   // Retry interval in days (default: 1)
  }
  waitDelayAfterRating?: number // Days to wait after rating (default: 60)
}

Basic Usage Examples

Direct Import and Use

// Import the component directly
import SoluCXSurveyWidget from 'solucx-survey-widget'

// Use in your template/JSX
<SoluCXSurveyWidget
  solu-cx-key="your-survey-key"
  widget-type="inline"
  widget-data='{"customer_id": "12345", "email": "[email protected]"}'
/>

Global Registration (Vue.js)

// main.js
import { createApp } from 'vue'
import SoluCXSurveyWidget from 'solucx-survey-widget'
import App from './App.vue'

const app = createApp(App)

// Register globally
app.component('SoluCXSurveyWidget', SoluCXSurveyWidget)

app.mount('#app')
<!-- Now you can use it anywhere without importing -->
<template>
  <div>
    <SoluCXSurveyWidget
      :solu-cx-key="surveyKey"
      widget-type="modal"
      :widget-data="customerData"
    />
  </div>
</template>

<script setup>
// No need to import when registered globally
const surveyKey = 'your-survey-key'
const customerData = {
  customer_id: '12345',
  email: '[email protected]'
}
</script>

Web Component (Vanilla HTML/JS)

<!DOCTYPE html>
<html>
<head>
  <title>SoluCX Survey</title>
</head>
<body>
  <!-- Include the widget -->
  <script type="module">
    import 'solucx-survey-widget'
  </script>
  
  <!-- Use the web component -->
  <solucx-survey-widget
    solu-cx-key="your-survey-key"
    widget-type="bottomBox"
    widget-data='{"customer_id": "12345", "email": "[email protected]"}'
    widget-options='{"width": 400, "height": 300}'
  ></solucx-survey-widget>

  <script>
    // Listen to events
    const widget = document.querySelector('solucx-survey-widget')
    
    widget.addEventListener('widgetCompleted', (event) => {
      console.log('Survey completed!')
      // Handle completion
    })
    
    widget.addEventListener('widgetError', (event) => {
      console.error('Widget error:', event.detail)
    })
  </script>
</body>
</html>

CDN Usage

<!DOCTYPE html>
<html>
<head>
  <title>SoluCX Survey - CDN</title>
</head>
<body>
  <!-- Load from CDN -->
  <script type="module" src="https://unpkg.com/solucx-survey-widget@latest/dist/index.js"></script>
  
  <!-- Use the component -->
  <solucx-survey-widget
    solu-cx-key="your-survey-key"
    widget-type="inline"
    widget-data='{"customer_id": "67890", "name": "John Doe"}'
  ></solucx-survey-widget>
</body>
</html>

Dynamic Component Creation

// Create widget programmatically
function createSurveyWidget(containerId, config) {
  const container = document.getElementById(containerId)
  
  if (!container) {
    console.error('Container not found')
    return
  }
  
  // Create the web component
  const widget = document.createElement('solucx-survey-widget')
  
  // Set properties
  widget.setAttribute('solu-cx-key', config.surveyKey)
  widget.setAttribute('widget-type', config.type || 'inline')
  widget.setAttribute('widget-data', JSON.stringify(config.data))
  
  if (config.options) {
    widget.setAttribute('widget-options', JSON.stringify(config.options))
  }
  
  // Add event listeners
  widget.addEventListener('widgetCompleted', config.onComplete || (() => {}))
  widget.addEventListener('widgetClosed', config.onClose || (() => {}))
  widget.addEventListener('widgetError', config.onError || (() => {}))
  
  // Append to container
  container.appendChild(widget)
  
  return widget
}

// Usage
createSurveyWidget('survey-container', {
  surveyKey: 'your-survey-key',
  type: 'modal',
  data: {
    customer_id: '12345',
    email: '[email protected]'
  },
  options: {
    width: 600,
    height: 400
  },
  onComplete: (userId) => {
    console.log('Survey completed by:', userId)
    // Redirect or show thank you message
  },
  onError: (error) => {
    console.error('Survey error:', error)
  }
})

Conditional Loading

// Load widget only when needed
async function loadSurveyWidget() {
  try {
    // Dynamic import
    await import('solucx-survey-widget')
    
    // Create and configure widget
    const widget = document.createElement('solucx-survey-widget')
    widget.setAttribute('solu-cx-key', 'your-survey-key')
    widget.setAttribute('widget-type', 'bottomBar')
    widget.setAttribute('widget-data', JSON.stringify({
      customer_id: '12345',
      email: '[email protected]'
    }))
    
    document.body.appendChild(widget)
    
  } catch (error) {
    console.error('Failed to load survey widget:', error)
  }
}

// Load on user interaction
document.getElementById('show-survey').addEventListener('click', loadSurveyWidget)

// Or load after page load
window.addEventListener('load', () => {
  setTimeout(loadSurveyWidget, 3000) // Show survey after 3 seconds
})

Framework Integration Examples

Vue.js

<template>
  <div>
    <SoluCXSurveyWidget
      :solu-cx-key="surveyKey"
      widget-type="inline"
      :widget-data="surveyData"
      :widget-options="options"
      @widget-opened="onWidgetOpened"
      @widget-closed="onWidgetClosed"
      @widget-completed="onWidgetCompleted"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import SoluCXSurveyWidget from 'solucx-survey-widget'

const surveyKey = 'your-survey-key'
const surveyData = ref({
  customer_id: '12345',
  email: '[email protected]',
  name: 'John Doe'
})

const options = ref({
  width: 600,
  height: 400
})

const onWidgetOpened = (userId) => {
  console.log('Widget opened for user:', userId)
}

const onWidgetClosed = () => {
  console.log('Widget closed')
}

const onWidgetCompleted = (userId) => {
  console.log('Survey completed by user:', userId)
}
</script>

Nuxt.js

1. Create a plugin (plugins/solucx-widget.client.js):

import SoluCXSurveyWidget from 'solucx-survey-widget'

export default defineNuxtPlugin(nuxtApp => {
  nuxtApp.vueApp.component('SoluCXSurveyWidget', SoluCXSurveyWidget)
})

2. Use in your component:

<template>
  <div>
    <ClientOnly>
      <SoluCXSurveyWidget
        :solu-cx-key="surveyKey"
        widget-type="modal"
        :widget-data="surveyData"
        @widget-completed="handleCompletion"
      />
    </ClientOnly>
  </div>
</template>

<script setup>
const surveyKey = 'your-survey-key'
const surveyData = {
  customer_id: '12345',
  email: '[email protected]'
}

const handleCompletion = (userId) => {
  console.log('Survey completed!', userId)
  // Navigate to thank you page
  await navigateTo('/thank-you')
}
</script>

React

1. Create a wrapper component (SoluCXWidget.jsx):

import React, { useEffect, useRef } from 'react'
import 'solucx-survey-widget'

const SoluCXWidget = ({ 
  soluCxKey, 
  widgetType = 'inline', 
  widgetData, 
  widgetOptions = {},
  onWidgetCompleted,
  onWidgetClosed,
  onWidgetError 
}) => {
  const widgetRef = useRef(null)

  useEffect(() => {
    const widget = widgetRef.current

    if (widget) {
      // Set properties
      widget.soluCxKey = soluCxKey
      widget.widgetType = widgetType
      widget.widgetData = JSON.stringify(widgetData)
      widget.widgetOptions = JSON.stringify(widgetOptions)

      // Add event listeners
      const handleCompleted = () => onWidgetCompleted?.(widgetData.customer_id)
      const handleClosed = () => onWidgetClosed?.()
      const handleError = (event) => onWidgetError?.(event.detail)

      widget.addEventListener('widgetCompleted', handleCompleted)
      widget.addEventListener('widgetClosed', handleClosed)
      widget.addEventListener('widgetError', handleError)

      // Cleanup
      return () => {
        widget.removeEventListener('widgetCompleted', handleCompleted)
        widget.removeEventListener('widgetClosed', handleClosed)
        widget.removeEventListener('widgetError', handleError)
      }
    }
  }, [soluCxKey, widgetType, widgetData, widgetOptions])

  return <solucx-survey-widget ref={widgetRef} />
}

export default SoluCXWidget

2. Use in your React component:

import React, { useState } from 'react'
import SoluCXWidget from './SoluCXWidget'

const SurveyPage = () => {
  const [surveyData] = useState({
    customer_id: '12345',
    email: '[email protected]',
    name: 'John Doe'
  })

  const handleSurveyCompleted = (userId) => {
    console.log('Survey completed by:', userId)
    // Redirect or show success message
  }

  return (
    <div className="survey-container">
      <h2>Customer Feedback</h2>
      <SoluCXWidget
        soluCxKey="your-survey-key"
        widgetType="inline"
        widgetData={surveyData}
        widgetOptions={{ width: 600, height: 400 }}
        onWidgetCompleted={handleSurveyCompleted}
      />
    </div>
  )
}

export default SurveyPage

Next.js

1. Create a dynamic component (components/SoluCXWidget.js):

import dynamic from 'next/dynamic'
import { useEffect, useRef } from 'react'

const SoluCXWidget = ({ soluCxKey, widgetType, widgetData, widgetOptions, onComplete }) => {
  const widgetRef = useRef(null)

  useEffect(() => {
    // Import the web component dynamically
    import('solucx-survey-widget')
  }, [])

  useEffect(() => {
    const widget = widgetRef.current
    if (widget) {
      widget.soluCxKey = soluCxKey
      widget.widgetType = widgetType
      widget.widgetData = JSON.stringify(widgetData)
      widget.widgetOptions = JSON.stringify(widgetOptions || {})

      const handleComplete = () => onComplete?.(widgetData.customer_id)
      widget.addEventListener('widgetCompleted', handleComplete)

      return () => widget.removeEventListener('widgetCompleted', handleComplete)
    }
  }, [soluCxKey, widgetType, widgetData, widgetOptions, onComplete])

  return <solucx-survey-widget ref={widgetRef} />
}

// Export as dynamic component to avoid SSR issues
export default dynamic(() => Promise.resolve(SoluCXWidget), { ssr: false })

2. Use in your page (pages/survey.js):

import SoluCXWidget from '../components/SoluCXWidget'
import { useRouter } from 'next/router'

export default function SurveyPage() {
  const router = useRouter()

  const surveyData = {
    customer_id: '12345',
    email: '[email protected]',
    transaction_id: 'tx_' + Date.now()
  }

  const handleSurveyComplete = (userId) => {
    console.log('Survey completed!', userId)
    router.push('/thank-you')
  }

  return (
    <div style={{ padding: '20px' }}>
      <h1>Customer Satisfaction Survey</h1>
      <SoluCXWidget
        soluCxKey="your-survey-key"
        widgetType="inline"
        widgetData={surveyData}
        widgetOptions={{ width: 700, height: 500 }}
        onComplete={handleSurveyComplete}
      />
    </div>
  )
}

Angular

1. Create a wrapper component (survey-widget.component.ts):

import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'

@Component({
  selector: 'app-survey-widget',
  template: `
    <solucx-survey-widget 
      #widget
      [attr.solu-cx-key]="soluCxKey"
      [attr.widget-type]="widgetType"
      [attr.widget-data]="widgetDataString"
      [attr.widget-options]="widgetOptionsString"
    ></solucx-survey-widget>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SurveyWidgetComponent implements OnInit {
  @Input() soluCxKey!: string
  @Input() widgetType: string = 'inline'
  @Input() widgetData: any = {}
  @Input() widgetOptions: any = {}
  
  @Output() widgetCompleted = new EventEmitter<string>()
  @Output() widgetClosed = new EventEmitter<void>()
  @Output() widgetError = new EventEmitter<string>()

  @ViewChild('widget', { static: true }) widget!: ElementRef

  get widgetDataString(): string {
    return JSON.stringify(this.widgetData)
  }

  get widgetOptionsString(): string {
    return JSON.stringify(this.widgetOptions)
  }

  async ngOnInit() {
    // Import the web component
    await import('solucx-survey-widget')
    
    // Add event listeners
    const widgetElement = this.widget.nativeElement
    
    widgetElement.addEventListener('widgetCompleted', () => {
      this.widgetCompleted.emit(this.widgetData.customer_id)
    })
    
    widgetElement.addEventListener('widgetClosed', () => {
      this.widgetClosed.emit()
    })
    
    widgetElement.addEventListener('widgetError', (event: any) => {
      this.widgetError.emit(event.detail)
    })
  }
}

2. Use in your component (survey.component.ts):

import { Component } from '@angular/core'
import { Router } from '@angular/router'

@Component({
  selector: 'app-survey',
  template: `
    <div class="survey-container">
      <h2>Customer Feedback</h2>
      <app-survey-widget
        [soluCxKey]="surveyKey"
        widgetType="inline"
        [widgetData]="surveyData"
        [widgetOptions]="surveyOptions"
        (widgetCompleted)="onSurveyCompleted($event)"
        (widgetError)="onSurveyError($event)"
      ></app-survey-widget>
    </div>
  `,
  styles: [`
    .survey-container {
      padding: 20px;
      max-width: 800px;
      margin: 0 auto;
    }
  `]
})
export class SurveyComponent {
  surveyKey = 'your-survey-key'
  
  surveyData = {
    customer_id: '12345',
    email: '[email protected]',
    name: 'John Doe'
  }
  
  surveyOptions = {
    width: 600,
    height: 400
  }

  constructor(private router: Router) {}

  onSurveyCompleted(userId: string) {
    console.log('Survey completed by:', userId)
    this.router.navigate(['/thank-you'])
  }

  onSurveyError(error: string) {
    console.error('Survey error:', error)
    // Handle error
  }
}

3. Update your module (app.module.ts):

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { SurveyWidgetComponent } from './survey-widget.component'

@NgModule({
  declarations: [
    SurveyWidgetComponent
  ],
  imports: [BrowserModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }

Events

The widget emits the following events:

| Event | Description | Payload | |-------|-------------|---------| | widgetOpened | Widget is displayed | userId: string | | widgetClosed | Widget is closed | - | | widgetCompleted | Survey completed | userId: string | | widgetError | Error occurred | error: string | | widgetResized | Widget height changed | height: number | | widgetPageChanged | Survey page changed | page: string |

Widget Types

  • inline: Embedded directly in page content
  • modal: Overlay modal with backdrop
  • bottomBar: Fixed bottom bar across full width
  • bottomBox: Fixed bottom-right corner box
  • bottomBoxLeft: Fixed bottom-left corner box

Development

# Install dependencies
npm install

# Run tests
npm test

# Build for production
npm run build

Support

For support and questions, please contact the SoluCX team or refer to the official documentation.