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

@feedvalue/vue

v0.1.10

Published

FeedValue Vue 3 SDK - Plugin and Composables for Vue 3+

Readme

@feedvalue/vue

Vue SDK for FeedValue feedback widget. Provides Plugin and Composables for Vue 3+.

Installation

npm install @feedvalue/vue
# or
pnpm add @feedvalue/vue
# or
yarn add @feedvalue/vue

Usage

Setup with Plugin

// main.ts
import { createApp } from 'vue';
import { createFeedValue } from '@feedvalue/vue';
import App from './App.vue';

const app = createApp(App);

app.use(createFeedValue({
  widgetId: 'your-widget-id',
  config: {
    theme: 'auto',
  },
}));

app.mount('#app');

Using the Composable

<script setup>
import { useFeedValue } from '@feedvalue/vue';

const { open, isReady, isOpen } = useFeedValue();
</script>

<template>
  <button @click="open" :disabled="!isReady">
    {{ isOpen ? 'Close' : 'Give Feedback' }}
  </button>
</template>

Headless Mode

For complete UI control, use headless mode. The SDK fetches config and provides all API methods but renders no DOM elements:

// main.ts
app.use(createFeedValue({
  widgetId: 'your-widget-id',
  headless: true, // No trigger button or modal rendered
}));
<script setup>
import { ref } from 'vue';
import { useFeedValue } from '@feedvalue/vue';

const { isReady, isOpen, open, close, submit, isSubmitting, isHeadless } = useFeedValue();
const message = ref('');

async function handleSubmit() {
  await submit({ message: message.value });
  message.value = '';
  close();
}
</script>

<template>
  <button @click="open" :disabled="!isReady">
    Feedback
  </button>

  <div v-if="isOpen" class="my-modal">
    <textarea v-model="message" placeholder="Your feedback..." />
    <button @click="handleSubmit" :disabled="isSubmitting">
      {{ isSubmitting ? 'Sending...' : 'Submit' }}
    </button>
    <button @click="close">Cancel</button>
  </div>
</template>

Standalone Usage (No Plugin)

<script setup>
import { useFeedValue } from '@feedvalue/vue';

// Pass widgetId directly when not using plugin
const { open, isReady } = useFeedValue('your-widget-id');
</script>

<template>
  <button @click="open" :disabled="!isReady">
    Feedback
  </button>
</template>

Programmatic Submission

<script setup>
import { ref } from 'vue';
import { useFeedValue } from '@feedvalue/vue';

const { submit, isSubmitting, error } = useFeedValue();
const message = ref('');

async function handleSubmit() {
  try {
    await submit({ message: message.value });
    message.value = '';
    console.log('Feedback submitted!');
  } catch (err) {
    console.error('Failed:', err);
  }
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <textarea v-model="message" placeholder="Your feedback..." />
    <button type="submit" :disabled="isSubmitting">
      {{ isSubmitting ? 'Submitting...' : 'Submit' }}
    </button>
    <p v-if="error" class="error">{{ error.message }}</p>
  </form>
</template>

Custom Fields

Custom fields allow you to collect structured data beyond the main feedback message. Custom fields must be defined in your widget configuration on the FeedValue dashboard before use.

  1. Go to your widget settings in the FeedValue dashboard
  2. Add custom fields with types: text, email, or emoji
  3. Use customFieldValues when submitting:
<script setup>
import { ref } from 'vue';
import { useFeedValue } from '@feedvalue/vue';

const { submit, isReady } = useFeedValue();
const name = ref('');
const category = ref('feature');

async function handleSubmit() {
  await submit({
    message: 'Detailed feedback',
    customFieldValues: {
      // Field IDs must match those defined in your widget configuration
      name: name.value,
      category: category.value,
    },
  });
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="name" placeholder="Your name" />
    <select v-model="category">
      <option value="bug">Bug Report</option>
      <option value="feature">Feature Request</option>
    </select>
    <button type="submit" :disabled="!isReady">Submit</button>
  </form>
</template>

Important: The field IDs in customFieldValues must match the field IDs defined in your widget configuration on the dashboard.

User Identification

Attach user context to feedback submissions. This data is not shown in the widget UI but is stored with the submission and visible in your FeedValue dashboard:

<script setup>
import { watch } from 'vue';
import { useFeedValue } from '@feedvalue/vue';

const props = defineProps<{ user: User | null }>();
const { identify, setData, reset } = useFeedValue();

watch(() => props.user, (user) => {
  if (user) {
    identify(user.id, {
      name: user.name,
      email: user.email,
      plan: user.plan,
    });
    setData({ company: user.company });
  } else {
    reset();
  }
}, { immediate: true });
</script>

User Data vs Custom Fields

  • User data (identify/setData): Hidden from users, automatically attached to submissions. Use for internal context like user IDs, subscription plans, etc.
  • Custom fields (customFieldValues): Shown as form inputs in the widget. Users fill these in themselves. Must be defined in widget configuration first.

Options API Support

<script>
export default {
  methods: {
    openFeedback() {
      // Access via global property
      this.$feedvalue?.open();
    },
  },
};
</script>

<template>
  <button @click="openFeedback">Feedback</button>
</template>

API Reference

createFeedValue(options)

Creates a Vue plugin for FeedValue.

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | widgetId | string | Yes | - | Widget ID from FeedValue dashboard | | apiBaseUrl | string | No | Production URL | Custom API URL (for self-hosted) | | config | Partial<FeedValueConfig> | No | - | Configuration overrides | | headless | boolean | No | false | Disable all DOM rendering |

useFeedValue(widgetId?, config?)

Composable to access FeedValue functionality.

Parameters:

| Param | Type | Description | |-------|------|-------------| | widgetId | string | Optional widget ID (not needed if plugin is installed) | | config | Partial<FeedValueConfig> | Optional config overrides |

Returns:

| Property | Type | Description | |----------|------|-------------| | instance | Readonly<ShallowRef<FeedValueInstance \| null>> | Raw instance | | isReady | Readonly<Ref<boolean>> | Widget initialized | | isOpen | Readonly<Ref<boolean>> | Modal is open | | isVisible | Readonly<Ref<boolean>> | Trigger is visible | | error | Readonly<Ref<Error \| null>> | Current error | | isSubmitting | Readonly<Ref<boolean>> | Submission in progress | | isHeadless | Readonly<Ref<boolean>> | Running in headless mode | | open | () => void | Open modal | | close | () => void | Close modal | | toggle | () => void | Toggle modal | | show | () => void | Show trigger | | hide | () => void | Hide trigger | | submit | (feedback) => Promise<void> | Submit feedback | | identify | (userId, traits?) => void | Identify user | | setData | (data) => void | Set user data | | reset | () => void | Reset user data |

Injection Keys

For advanced usage with inject():

import { inject } from 'vue';
import { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from '@feedvalue/vue';

// Get raw FeedValue instance
const instance = inject(FEEDVALUE_KEY);

// Get plugin options
const options = inject(FEEDVALUE_OPTIONS_KEY);

Nuxt Integration

Works with Nuxt 3 and Nuxt 4. Create a plugin file:

// plugins/feedvalue.client.ts
import { createFeedValue } from '@feedvalue/vue';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(createFeedValue({
    widgetId: 'your-widget-id',
  }));
});

For headless mode in Nuxt:

// plugins/feedvalue.client.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(createFeedValue({
    widgetId: 'your-widget-id',
    headless: true, // Build your own UI
  }));
});

The .client.ts suffix ensures the plugin only runs on the client side.

SSR Support

The SDK handles SSR automatically:

  • Plugin only initializes on client side
  • Composable returns safe defaults during SSR
  • No hydration mismatches
<script setup>
import { useFeedValue } from '@feedvalue/vue';

const { isReady } = useFeedValue();
// isReady.value is false during SSR
</script>

<template>
  <!-- Safe to use in SSR context -->
  <button :disabled="!isReady">Feedback</button>
</template>

Default vs Headless Mode

| Feature | Default Mode | Headless Mode | |---------|--------------|---------------| | Trigger button | Dashboard-styled | You build it | | Modal | Dashboard-styled | You build it | | API methods | Available | Available | | User tracking | Available | Available | | Dashboard config | Fetched | Fetched |

Use headless: true when you want complete control over the UI.

Requirements

  • Vue 3.3.0 or higher

License

MIT