Intégration React
Composant React réutilisable pour le widget Ekoo
Le widget charge automatiquement sa configuration depuis le backoffice. Les attributs d'apparence sont des surcharges optionnelles — inutile de les définir si le backoffice est configuré.
Attributs principaux
data-ekooReqstring
UUID du site Ekoo. Visible dans le backoffice → Paramètres du site.
data-ekoo-product-idReqstring
Référence produit (doit correspondre exactement au catalogue Ekoo).
data-ekoo-localestring·default:
autoCode langue : fr, en, es, it, de, ar, cn, tw, hk, jp, kr, nl, tr, pl, pt, lu, be, ru. "auto" = détection navigator.language.
data-ekoo-variantstring
Référence stable d’une configuration widget. Le produit, ses audios et ses reviewers restent pilotés par data-ekoo-product-id ; seul l’habillage change.
data-ekoo-review-idstring
ID d'un avis audio spécifique. Si omis, le premier avis publié est utilisé.
data-ekoo-on-eventstring (fn name)
Nom d'une fonction globale window appelée à chaque événement widget (printed, played-0, played-25…).
Apparence — surcharges backoffice
data-ekoo-directionnormal | reverse·default:
normalSens d'expansion. normal = gauche→droite, reverse = droite→gauche.
data-ekoo-scalenumber·default:
1Facteur de zoom (ex: "1.2" pour 20% plus grand).
data-ekoo-animationstring·default:
pulseType d'animation de l'icône au repos.
data-ekoo-animation-durationstring·default:
continuousDurée de l'animation.
data-ekoo-always-openboolean·default:
falseSi "true", le widget reste toujours déplié.
data-ekoo-show-imageboolean·default:
trueAfficher ou masquer l'image produit dans le widget.
data-ekoo-not-fully-clickableboolean·default:
falseSi "true", seul le bouton lecture est cliquable.
data-ekoo-autoplayboolean·default:
falseLecture audio automatique au chargement.
data-ekoo-show-transcriptboolean·default:
falseAfficher un bouton pour lire la transcription.
data-ekoo-show-speed-buttonboolean·default:
falseAfficher un contrôle de vitesse de lecture.
data-ekoo-closed-state-main-textstring
Texte CTA principal affiché quand le widget est replié.
data-ekoo-closed-state-secondary-textstring
Texte secondaire sous le CTA quand le widget est replié.
SPA & Shadow DOM
data-ekoo-modespa | static·default:
autoForce le mode rendu. Auto-détecté (Next.js, Nuxt, React, Vue, Angular, Sapper). À utiliser seulement si la détection auto échoue.
data-shadow-modeopen | closed·default:
open"open" (par défaut) permet l'inspection, l'accès CSS externe et le tracking analytics. Définir à "closed" pour isoler complètement le widget.
Config JS globale
window.EKOO_FORCE_SPA = trueForce le mode SPA globalement (alternative à data-ekoo-mode="spa" sur chaque widget).
window.ekooShadowMode = "open"Shadow DOM mode global (alternative à data-shadow-mode sur chaque widget).
1. Déclarations TypeScript
Ajoutez les types pour les fonctions globales Ekoo afin d'éviter les erreurs TypeScript :
types/ekoo.d.ts
typescript
1declare global {2 interface Window {3 ekooLoad?: () => void4 ekooUnload?: () => void5 ekooReload?: () => void6 }7}89export {}2. Composant EkooWidget
components/EkooWidget.tsx
tsx
1'use client' // Next.js App Router only23import { useEffect, useRef } from 'react'45const EKOO_SCRIPT_URL = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js'67interface EkooWidgetProps {8 websiteId: string9 productId: string10 locale?: string11}1213export function EkooWidget({14 websiteId,15 productId,16 locale = 'fr',17}: EkooWidgetProps) {18 const containerRef = useRef<HTMLDivElement>(null)1920 useEffect(() => {21 // Load the script if not already present22 let script = document.querySelector<HTMLScriptElement>(23 `script[src="${EKOO_SCRIPT_URL}"]`24 )2526 if (!script) {27 script = document.createElement('script')28 script.src = EKOO_SCRIPT_URL29 script.defer = true30 document.head.appendChild(script)31 }3233 // Initialize the widget once the script is loaded34 const init = () => window.ekooLoad?.()3536 if (script.dataset.loaded === 'true') {37 init()38 } else {39 script.addEventListener('load', () => {40 script!.dataset.loaded = 'true'41 init()42 })43 }4445 // Cleanup on unmount46 return () => {47 window.ekooUnload?.()48 }49 }, [websiteId, productId, locale])5051 return (52 <div53 ref={containerRef}54 data-ekoo={websiteId}55 data-ekoo-product-id={productId}56 data-ekoo-locale={locale}57 />58 )59}3. Utilisation
app/product/[id]/page.tsx
tsx
1import { EkooWidget } from '@/components/EkooWidget'23export default function ProductPage({ params }: { params: { id: string } }) {4 return (5 <main>6 <h1>My product</h1>7 <EkooWidget8 websiteId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"9 productId={params.id}10 locale="fr"11 />12 </main>13 )14}4. Navigation SPA (React Router)
Dans une SPA, le composant se monte et se démonte au changement de route. Le useEffect du composant ci-dessus gère déjà ce cas :
- Au montage :
ekooLoad()initialise le widget. - Au démontage :
ekooUnload()nettoie les listeners.
⚠️
Ré-initialisation au changement de route
Si le productId change sans démontage du composant (ex. navigation entre deux produits sur la même route), appelez window.ekooReload() pour rafraîchir le widget. Le composant ci-dessus le gère via la dépendance productId dans le useEffect.
5. Notes pour Next.js
- App Router : ajoutez
'use client'en haut du fichier composant (déjà fait dans l'exemple). - Pages Router : utilisez
dynamic(() => import(...), { ssr: false })pour désactiver le SSR si vous rencontrez des erreurswindow is not defined. - Le script Ekoo manipule le DOM — il doit s'exécuter côté client uniquement.
Import dynamique (Pages Router)
tsx
1import dynamic from 'next/dynamic'23const EkooWidget = dynamic(4 () => import('@/components/EkooWidget').then(m => m.EkooWidget),5 { ssr: false }6)78export default function ProductPage() {9 return <EkooWidget websiteId="..." productId="..." />10}