Skip to content

Framework guides

The <powsoo-voice> custom element works in any environment. The embed snippet is the same everywhere — these are framework-specific placement notes.

Plain HTML

Paste directly before </body>:

<powsoo-voice widget-id="wid_abc123"></powsoo-voice>
<script>
(() => {
const d = document, s = d.createElement('script');
s.type = 'module';
s.src = 'https://w.powsoo.com/widget.js';
d.head.append(s);
})();
</script>

React

Place the element in JSX. Guard the bootstrap script so it only runs once:

CallButton.tsx
export function CallButton() {
return (
<>
{/* @ts-expect-error — custom element */}
<powsoo-voice widget-id="wid_abc123" />
<script
dangerouslySetInnerHTML={{
__html: `(() => {
if (window.__powsooLoaded) return;
window.__powsooLoaded = true;
const d = document, s = d.createElement('script');
s.type = 'module';
s.src = 'https://w.powsoo.com/widget.js';
d.head.append(s);
})();`,
}}
/>
</>
);
}

Add a global type declaration so TypeScript recognises the custom element:

src/powsoo.d.ts
declare namespace JSX {
interface IntrinsicElements {
'powsoo-voice': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & { 'widget-id': string },
HTMLElement
>;
}
}

Next.js

Use Next.js’s <Script> component with strategy="lazyOnload" to avoid blocking the page:

import Script from 'next/script';
export function CallButton() {
return (
<>
{/* @ts-expect-error — custom element */}
<powsoo-voice widget-id="wid_abc123" />
<Script id="powsoo-bootstrap" strategy="lazyOnload">{`
(() => {
const d = document, s = d.createElement('script');
s.type = 'module';
s.src = 'https://w.powsoo.com/widget.js';
d.head.append(s);
})();
`}</Script>
</>
);
}

Vue / Nuxt

<template>
<powsoo-voice widget-id="wid_abc123" />
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
onMounted(() => {
if (document.querySelector('script[src*="powsoo"]')) return;
const s = document.createElement('script');
s.type = 'module';
s.src = 'https://w.powsoo.com/widget.js';
document.head.append(s);
});
</script>

Add to vite.config.ts to suppress the unknown element warning:

vite.config.ts
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('powsoo-'),
},
},
})

Webflow

  1. In the Webflow designer, drag an Embed element to the page.
  2. Paste the full snippet (both the <powsoo-voice> tag and the <script> block) into the embed.
  3. Publish.

WordPress

Paste the snippet into Appearance → Theme file editor → footer.php just before </body>, or use a plugin that supports custom code injection (e.g. Insert Headers and Footers).

Squarespace

Go to Settings → Advanced → Code Injection → Footer and paste the snippet. It loads on every page.

Shopify

Add the snippet to your theme’s theme.liquid just before </body>.