Skip to content

Vue Integration

Add FeedValue to your Vue 3 application with full TypeScript support.

Coming Soon

The @feedvalue/vue package is currently in development. Check back soon for availability on npm. In the meantime, use the script tag method.

Installation

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

Basic Usage

Install the plugin and use the composable:

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

app.mount('#app');
vue
<script setup>
import { useFeedValue } from '@feedvalue/vue';

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

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

Plugin Options

OptionTypeDefaultDescription
widgetIdstringrequiredYour widget ID from the dashboard
apiBaseUrlstring-Custom API URL (for self-hosted)
configobject-Configuration overrides
headlessbooleanfalseDisable default UI rendering

Composable Return Values

The useFeedValue composable returns reactive refs and methods:

ts
const {
  // Reactive State (Ref<>)
  isReady,      // Widget is ready (config loaded)
  isOpen,       // Modal is currently open
  isVisible,    // Trigger button is visible
  isSubmitting, // Submission in progress
  isHeadless,   // Running in headless mode
  error,        // Current error (if any)
  instance,     // FeedValue instance (advanced usage)

  // Methods
  open,         // Open the feedback modal
  close,        // Close the feedback modal
  toggle,       // Toggle the modal open/closed
  show,         // Show the trigger button
  hide,         // Hide the trigger button
  submit,       // Submit feedback programmatically
  identify,     // Identify the current user
  setData,      // Set user data
  reset,        // Reset user data
} = useFeedValue();

Headless Mode

For complete UI control, use headless mode:

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

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

const handleSubmit = async () => {
  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" />
    <button @click="handleSubmit" :disabled="isSubmitting">
      {{ isSubmitting ? 'Sending...' : 'Submit' }}
    </button>
    <button @click="close">Cancel</button>
  </div>
</template>

Custom Fields (User-Facing Form Inputs)

Custom fields are form inputs shown in the widget UI that users fill in themselves. They must be defined in your widget configuration on the FeedValue dashboard.

When to Use Custom Fields vs User Identification

Use CaseSolution
Collect user's name/email in the formCustom Fields - define in dashboard, user fills in
Attach logged-in user's info automaticallyUser Identification - use identify(), hidden from UI
Let user select feedback categoryCustom Fields - define dropdown in dashboard
Track internal account IDsUser Identification - use setData(), hidden from UI

Setting Up Custom Fields

  1. Go to your widget settings in the FeedValue dashboard
  2. Add custom fields with types: text, email, or emoji
  3. Configure labels, placeholders, and whether fields are required
  4. The fields will automatically appear in the widget modal

Headless Mode: Submitting Custom Field Values

When using headless mode with your own UI, use customFieldValues to submit responses:

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

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

const handleSubmit = async () => {
  await submit({
    message: 'Detailed feedback message',
    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>

Custom Fields Must Be Defined First

The field IDs in customFieldValues (e.g., name, category) should match 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.

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

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

watch(() => props.user, (user) => {
  if (user) {
    identify(user.id, {
      email: user.email,
      name: user.name,
      plan: user.plan,
      company: user.company,
    });
  }
}, { 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.

Standalone Usage (Without Plugin)

You can also use the composable without installing the plugin:

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

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

Options API

If you prefer Options API, access via $feedvalue:

vue
<script>
export default {
  mounted() {
    // Access the FeedValue instance
    this.$feedvalue?.open();
  },
  methods: {
    submitFeedback() {
      this.$feedvalue?.submit({ message: 'Great app!' });
    },
  },
};
</script>

Nuxt 3

Create a client-side plugin:

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

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

Use in your layout or components:

vue
<!-- layouts/default.vue -->
<script setup>
import { useFeedValue } from '@feedvalue/vue';

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

<template>
  <div>
    <slot />
    <button @click="open" :disabled="!isReady" class="feedback-button">
      Feedback
    </button>
  </div>
</template>

For headless mode in Nuxt:

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

TypeScript Support

Full TypeScript support is included:

ts
import type {
  FeedValuePluginOptions,
  UseFeedValueReturn,
} from '@feedvalue/vue';

import type {
  FeedbackData,
  UserTraits,
} from '@feedvalue/vue';

const handleSubmit = (feedback: FeedbackData) => {
  console.log(feedback.message);
  console.log(feedback.sentiment);
};

Comparison: Default vs Headless

FeatureDefault ModeHeadless Mode
Trigger buttonDashboard-styledYou build it
ModalDashboard-styledYou build it
API methodsAvailableAvailable
User trackingAvailableAvailable
Dashboard configFetchedFetched

TIP

Use headless: true when you want complete control over the UI, or when you have security concerns about external code injecting DOM elements.

Built with care by SarverEnterprises