Svelte / SvelteKit Integration

Svelte component for the Ekoo widget with lifecycle management

The widget auto-loads its config from the backoffice. Appearance attributes are optional overrides — no need to set them if the backoffice is configured.
Core attributes
data-ekooReq
string
Your Ekoo website UUID. Found in the backoffice → Site settings.
data-ekoo-product-idReq
string
Product reference (must match exactly what is in your Ekoo catalog).
data-ekoo-locale
string·default: auto
Locale code: fr, en, es, it, de, ar, cn, tw, hk, jp, kr, nl, tr, pl, pt, lu, be, ru. "auto" = navigator.language detection.
data-ekoo-variant
string
Stable reference of a widget configuration. The product, its audios, and its reviewers still come from data-ekoo-product-id; only the widget styling changes.
data-ekoo-review-id
string
ID of a specific audio review. If omitted, the first published review is used.
data-ekoo-on-event
string (fn name)
Name of a global window function called on each widget event (printed, played-0, played-25…).
Appearance — backoffice overrides
data-ekoo-direction
normal | reverse·default: normal
Expansion direction. normal = left-to-right, reverse = right-to-left.
data-ekoo-scale
number·default: 1
Scale factor (e.g. "1.2" for 20% larger).
data-ekoo-animation
string·default: pulse
Animation type for the widget icon at rest.
data-ekoo-animation-duration
string·default: continuous
Animation duration.
data-ekoo-always-open
boolean·default: false
If "true", the widget stays permanently expanded.
data-ekoo-show-image
boolean·default: true
Show or hide the product image in the widget.
data-ekoo-not-fully-clickable
boolean·default: false
If "true", only the play button is clickable.
data-ekoo-autoplay
boolean·default: false
Automatically start audio playback on load.
data-ekoo-show-transcript
boolean·default: false
Show a button to read the audio transcript.
data-ekoo-show-speed-button
boolean·default: false
Show a playback speed control.
data-ekoo-closed-state-main-text
string
Main CTA text shown when the widget is collapsed.
data-ekoo-closed-state-secondary-text
string
Secondary text below the CTA when the widget is collapsed.
SPA & Shadow DOM
data-ekoo-mode
spa | static·default: auto
Forces rendering mode. Auto-detected (Next.js, Nuxt, React, Vue, Angular, Sapper). Only use if auto-detection fails.
data-shadow-mode
open | closed·default: open
"open" (default) enables inspection, external CSS access and analytics tracking. Set to "closed" to fully isolate the widget.
Global JS config
window.EKOO_FORCE_SPA = true
Forces SPA mode globally (alternative to data-ekoo-mode="spa" on each widget).
window.ekooShadowMode = "open"
Global Shadow DOM mode (alternative to data-shadow-mode on each widget).

1. EkooWidget Component

Create a Svelte component that dynamically loads the script and uses onMount / onDestroy to manage the lifecycle.

src/lib/components/EkooWidget.svelte
svelte
1<script lang="ts">
2 import { onMount, onDestroy } from 'svelte'
3
4 export let websiteId: string
5 export let productId: string
6 export let locale: string = 'fr'
7
8 const SCRIPT_URL = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js'
9
10 onMount(() => {
11 let script = document.querySelector<HTMLScriptElement>(
12 `script[src="${SCRIPT_URL}"]`
13 )
14
15 if (!script) {
16 script = document.createElement('script')
17 script.src = SCRIPT_URL
18 script.defer = true
19 document.head.appendChild(script)
20
21 script.addEventListener('load', () => {
22 window.ekooLoad?.()
23 })
24 } else {
25 window.ekooLoad?.()
26 }
27 })
28
29 onDestroy(() => {
30 window.ekooUnload?.()
31 })
32</script>
33
34<ekoo-widget
35 data-ekoo={websiteId}
36 data-ekoo-product-id={productId}
37 data-ekoo-locale={locale}
38></ekoo-widget>

2. Usage in a Page

src/routes/product/[id]/+page.svelte
svelte
1<script lang="ts">
2 import EkooWidget from '$lib/components/EkooWidget.svelte'
3 import type { PageData } from './$types'
4
5 export let data: PageData
6</script>
7
8<h1>{data.product.name}</h1>
9
10<EkooWidget
11 websiteId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
12 productId={data.product.id}
13 locale="fr"
14/>

3. SvelteKit Navigation

SvelteKit performs client-side navigations (soft navigation). When the user moves from one product to another, the component may not be destroyed and recreated. Use afterNavigate to reload the widget after each navigation:

SvelteKit navigation handling
svelte
1<script lang="ts">
2 import { onMount, onDestroy } from 'svelte'
3 import { afterNavigate } from '$app/navigation'
4
5 export let websiteId: string
6 export let productId: string
7 export let locale: string = 'fr'
8
9 const SCRIPT_URL = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js'
10
11 function loadScript() {
12 let script = document.querySelector<HTMLScriptElement>(
13 `script[src="${SCRIPT_URL}"]`
14 )
15 if (!script) {
16 script = document.createElement('script')
17 script.src = SCRIPT_URL
18 script.defer = true
19 document.head.appendChild(script)
20 script.addEventListener('load', () => window.ekooLoad?.())
21 } else {
22 window.ekooLoad?.()
23 }
24 }
25
26 onMount(() => loadScript())
27 onDestroy(() => window.ekooUnload?.())
28
29 // Reload the widget after each SvelteKit navigation
30 afterNavigate(() => {
31 window.ekooReload?.()
32 })
33</script>
34
35<ekoo-widget
36 data-ekoo={websiteId}
37 data-ekoo-product-id={productId}
38 data-ekoo-locale={locale}
39></ekoo-widget>
💡

Script loading strategy

The widget-4.0.0-standalone.js script should only be loaded once. The component checks whether the script is already present in the DOM before adding it. On subsequent navigations, only ekooLoad() or ekooReload() is called.

⚠️

Re-initialization

If the widget shows visual inconsistencies after several product changes, call window.ekooReload() to force a complete re-initialization.

Go Further

Svelte — Documentation — Ekoo