Framework Integration

The <cs-voice-survey> custom element works in any framework. Here are integration guides for the most popular ones.

Vanilla HTML (CDN)

The simplest integration — no build step required.

<!doctype html>
<html>
  <head>
    <script src="https://cdn.dev.canaryspeech.com/v/latest/voice-survey.min.js"></script>
  </head>
  <body>
    <cs-voice-survey
      base-url="https://rest.eus.canaryspeech.com"
      access-token="eyJ..."
      project-id="proj_abc123"
      subject-id="user_xyz"
    ></cs-voice-survey>

    <script>
      document.querySelector("cs-voice-survey").addEventListener("completed", (e) => {
        console.log("Done!", e.detail);
      });
    </script>
  </body>
</html>

React 18

React 18 does not forward custom element events through its synthetic event system. Attach listeners via useRef + useEffect.

import { useEffect, useRef } from "react";
import "cs-voice-survey-component";

export function VoiceSurveyWrapper() {
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    const onCompleted = (e: Event) => {
      const { assessmentId, scores } = (e as CustomEvent).detail;
      console.log("Completed:", assessmentId, scores);
    };

    el.addEventListener("completed", onCompleted);
    return () => el.removeEventListener("completed", onCompleted);
  }, []);

  return (
    <cs-voice-survey
      ref={ref}
      base-url="https://rest.eus.canaryspeech.com"
      access-token="eyJ..."
      project-id="proj_abc123"
      subject-id="user_xyz"
    />
  );
}

React 19+

React 19 added native custom element support — events and properties work without wrappers.

import "cs-voice-survey-component";

export function VoiceSurveyWrapper() {
  return (
    <cs-voice-survey
      base-url="https://rest.eus.canaryspeech.com"
      access-token="eyJ..."
      project-id="proj_abc123"
      subject-id="user_xyz"
      oncompleted={(e) => console.log("Done!", e.detail)}
    />
  );
}

SvelteKit

<script lang="ts">
  import "cs-voice-survey-component";

  function handleCompleted(e: CustomEvent) {
    console.log("Completed:", e.detail);
  }
</script>

<cs-voice-survey
  base-url="https://rest.eus.canaryspeech.com"
  access-token="eyJ..."
  project-id="proj_abc123"
  subject-id="user_xyz"
  on:completed={handleCompleted}
></cs-voice-survey>

Vue 3

<template>
  <cs-voice-survey
    base-url="https://rest.eus.canaryspeech.com"
    access-token="eyJ..."
    project-id="proj_abc123"
    subject-id="user_xyz"
    @completed="handleCompleted"
  />
</template>

<script setup lang="ts">
import "cs-voice-survey-component";

function handleCompleted(e: CustomEvent) {
  console.log("Completed:", e.detail);
}
</script>

In vite.config.ts, tell Vue to treat cs-voice-survey as a custom element:

import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => tag === "cs-voice-survey",
        },
      },
    }),
  ],
});

Angular

Add CUSTOM_ELEMENTS_SCHEMA to your module or standalone component:

import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";
import "cs-voice-survey-component";

@Component({
  selector: "app-survey",
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <cs-voice-survey
      base-url="https://rest.eus.canaryspeech.com"
      access-token="eyJ..."
      project-id="proj_abc123"
      subject-id="user_xyz"
      (completed)="onCompleted($event)"
    ></cs-voice-survey>
  `,
})
export class SurveyComponent {
  onCompleted(e: CustomEvent) {
    console.log("Completed:", e.detail);
  }
}

Aurelia 2

Aurelia treats unknown elements as custom elements automatically.

<cs-voice-survey
  base-url="https://rest.eus.canaryspeech.com"
  access-token.bind="accessToken"
  project-code.bind="projectCode"
  subject-name.bind="subjectName"
  @completed.trigger="onCompleted($event)"
></cs-voice-survey>

Use .trigger (not .delegate) for custom events from web components.

Alpine.js

<div x-data="{ init() {
    this.$refs.survey.addEventListener('completed', (e) => {
      console.log('Scores:', e.detail.scores);
    });
  }
}">
  <cs-voice-survey
    x-ref="survey"
    base-url="https://rest.eus.canaryspeech.com"
    :access-token="accessToken"
    :project-code="projectCode"
    :subject-name="subjectName"
  ></cs-voice-survey>
</div>