Appearance
Vue
Das Paket @pollyou/vue bindet PollYou-Umfragen als Vue-Komponente ein. Es kapselt das Web Component <pollyou-survey> aus @pollyou/embed-core, unterstützt Vue 3.4 und neuer und funktioniert mit Server-Side Rendering (Nuxt).
Installation
bash
npm install @pollyou/vue
# oder
pnpm add @pollyou/vuevue ist Peer-Abhängigkeit. @pollyou/embed-core wird automatisch mitinstalliert und erst im Browser nachgeladen. Eine Konfiguration von compilerOptions.isCustomElement ist nicht nötig: Die Komponente erzeugt das Element per Render-Funktion, der Template-Compiler bekommt <pollyou-survey> nie zu sehen.
Einbinden
vue
<script setup lang="ts">
import { PollYouSurvey } from '@pollyou/vue'
function onComplete(detail: { responseId: string | null }) {
console.log('Antwort gespeichert', detail.responseId)
}
</script>
<template>
<PollYouSurvey
survey-id="AbC123xyz0"
api-base="https://app.pollyou.org"
locale="de"
@complete="onComplete"
/>
</template>Den passenden Code mit allen gewählten Optionen erzeugt der Einbetten-Dialog im Dashboard (Reiter „Vue“).
Plugin mit Vorgaben
Optional legt das Plugin app-weite Vorgaben fest (Props der Komponente haben Vorrang) und registriert <PollYouSurvey> global:
ts
import { createApp } from 'vue'
import { PollYou } from '@pollyou/vue'
import App from './App.vue'
createApp(App).use(PollYou, { apiBase: 'https://app.pollyou.org', locale: 'de' }).mount('#app')Als Vorgabe taugt jede Prop außer surveyId und open.
Props
| Prop | Typ | Bedeutung |
|---|---|---|
survey-id | string (Pflicht) | Öffentliche ID der Umfrage. |
embed-id | string | Embed-Konfiguration (erlaubte Domains, Vorgaben). |
api-base | string | Origin der Collector-API, z. B. https://app.pollyou.org. |
mode | 'inline' | 'popup' | 'slider' | 'fullpage' | Darstellung, Standard inline; Overlays sichtbar solange open. Auslöser (Verzögerung, Scrolltiefe …) nur über die Embed-Konfiguration, siehe Overlays. |
v-model:open | boolean | Sichtbarkeit des Popups. Weglassen, wenn usePollYou() das Popup steuert. |
locale | string | Sprache, Standard: Sprache der Seite bzw. des Browsers. |
theme | 'auto' | 'light' | 'dark' | Farbschema, Standard auto. |
show-results | boolean | false blendet Ergebnisse aus, auch wenn die Umfrage sie zeigt. |
live-results | boolean | Angezeigte Ergebnisse live aktualisieren. |
identity-token | string | Signiertes Identitäts-Token des angemeldeten Nutzers. |
meta | Record<string, string | number | boolean> | Zusatzdaten zur Antwort (max. 20 Schlüssel). |
hidden | Record<string, string | number | boolean> | Versteckte Felder, z. B. { 'user-id': 42 } → hidden-user-id. Schlüssel werden kleingeschrieben. |
channel | string | Kanal in der Auswertung, Standard vue (oder die Plugin-Vorgabe). |
Weitere Attribute wie class, style oder hidden-user-id="42" landen unverändert auf dem Element. Gestalten lässt sich die Umfrage über das Theme im Dashboard und über ::part()-Selektoren (siehe Einbettung per Script).
Ereignisse
Die Nutzlast ist jeweils detail des ursprünglichen pollyou:*-Ereignisses.
| Ereignis | detail |
|---|---|
@ready | { surveyId, type, status } |
@start | { surveyId } (erste Antwort) |
@answer | { surveyId, questionKey, answer } |
@complete | { surveyId, responseId, results } |
@close | { surveyId, mode } |
@error | { surveyId, phase: 'load' | 'submit', status } |
@update:open | false, wenn sich ein kontrolliertes Popup schließt |
Popup
Mit v-model:open:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { PollYouSurvey } from '@pollyou/vue'
const open = ref(false)
</script>
<template>
<button type="button" @click="open = true">Feedback geben</button>
<PollYouSurvey survey-id="AbC123xyz0" mode="popup" v-model:open="open" />
</template>Oder imperativ mit dem Composable usePollYou():
vue
<script setup lang="ts">
import { PollYouSurvey, usePollYou } from '@pollyou/vue'
const { survey, open, completed, lastEvent } = usePollYou()
</script>
<template>
<button type="button" :disabled="completed" @click="open">Feedback geben</button>
<PollYouSurvey ref="survey" survey-id="AbC123xyz0" mode="popup" />
<p v-if="lastEvent?.type === 'complete'">Danke!</p>
</template>usePollYou() liefert survey (Template-Ref), element, open(), close(), isOpen, lastEvent ({ type, detail } des letzten pollyou:*-Ereignisses), completed und die Plugin-Vorgaben options.
Identitäts-Token
Für „eine Antwort pro Kunde“ oder Umfragen nur für angemeldete Nutzer erzeugt Ihr Server ein signiertes Identitäts-Token – das Embed-Secret gehört nie in den Browser. In Nuxt etwa über eine Server-Route:
ts
// server/api/pollyou-token.get.ts
import { SignJWT } from 'jose'
export default defineEventHandler(async (event) => {
const user = await requireUser(event)
return new SignJWT({})
.setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
.setSubject(String(user.id))
.setExpirationTime('10m')
.sign(new TextEncoder().encode(process.env.POLLYOU_EMBED_SECRET))
})vue
<script setup lang="ts">
const { data: token } = await useFetch<string>('/api/pollyou-token')
</script>
<template>
<PollYouSurvey survey-id="AbC123xyz0" :identity-token="token ?? undefined" />
</template>SSR und Nuxt
Beim Server-Rendering greift die Komponente auf keine Browser-API zu; es entsteht nur das leere Tag
<pollyou-survey>(mit durchgereichten Attributen wieclass). Attribute und das Nachladen von@pollyou/embed-corepassieren erst im Browser (onMounted). Ein<ClientOnly>ist nicht nötig.In Nuxt lässt sich das Plugin in
plugins/pollyou.tsregistrieren:tsimport { PollYou } from '@pollyou/vue' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(PollYou, { apiBase: 'https://app.pollyou.org' }) })Für einen festen Platz ohne Layoutsprung empfiehlt sich eine Mindesthöhe, z. B.
style="min-height: 320px".
Beispiel-App
Ein lauffähiges Beispiel liegt im Playground: frontend/apps/playground/vue (Vue 3 + Vite, Plugin mit Vorgaben, alle Ereignisse im Protokoll).
Fehlersuche
- Die Umfrage bleibt leer oder zeigt „nicht gefunden“: Nur veröffentlichte Umfragen sind öffentlich; ein Entwurf oder eine archivierte Umfrage liefert 404. Das Ereignis
@errormeldet{ phase: 'load', status }. - Fehler „blocked by CORS policy“ oder
403 origin_not_allowed: Die Embed-Konfiguration erlaubt nur bestimmte Origins. Tragen Sie die Origin Ihrer Seite ein – mit Schema und Port, also auch den lokalen Dev-Server (z. B.http://localhost:5173).api-baseist die Origin der API ohne Pfad (https://app.pollyou.org, nicht…/api). - Content-Security-Policy: Erlauben Sie die API in
connect-src(z. B.connect-src 'self' https://app.pollyou.org, für Live-Ergebnisse zusätzlich den Hub).script-srcbraucht keinen Eintrag:@pollyou/embed-coreist Teil Ihres Bundles und wird als eigener Chunk von Ihrer Origin nachgeladen. Die Styles setzt das Web-Component per Constructable Stylesheets und CSSOM,'unsafe-inline'instyle-srcist nicht nötig – nur eigenes Theme-CSS wird als<style>eingefügt und fehlt ohne'unsafe-inline'(die Umfrage funktioniert trotzdem). Das Captcha kommt ohne Worker undevalaus. - Lokal in Chrome keine Verbindung zur API: Chrome blockiert mit Local Network Access Anfragen von öffentlichen Seiten an
localhost. Die Seite muss selbst lokal laufen (localhost/127.0.0.1), wie die Apps im Playground. - Nuxt/SSR: leeres Element im HTML: Das ist gewollt – der Server rendert nur
<pollyou-survey>, die Umfrage lädt nach dem Mounten im Browser. Für einen festen Platz ohne Layoutsprung eine Mindesthöhe setzen. - Hydration-Warnungen: Entstehen, wenn Props auf dem Server anders berechnet werden als im Browser, etwa aus
window.location. In Nuxt die Query mituseRoute()lesen, sonst erst inonMountedsetzen. - „Failed to resolve component: pollyou-survey“: Tritt nur auf, wenn
<pollyou-survey>direkt im Template steht. Verwenden Sie<PollYouSurvey>aus dem Paket;compilerOptions.isCustomElementist dann nicht nötig.