Skip to content

Multi-Framework Integrations Guide ​

<oim-player> and <ovm-player> are standard W3C Custom Elements that integrate seamlessly into any modern frontend framework. Below are production-ready code patterns for each popular web stack.


1. React 19 & Next.js (App Router / Pages) ​

In React applications, register the web component inside an effect to ensure client-side hydration:

tsx
'use client';

import React, { useEffect, useRef } from 'react';
import '@oim-media/player-oim';

interface OimViewerProps {
  src: string;
  lang?: string;
  onAction?: (actionName: string) => void;
}

export function OimViewer({ src, lang = 'en', onAction }: OimViewerProps) {
  const playerRef = useRef<HTMLElement>(null);

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

    const handleAction = (e: Event) => {
      const customEvent = e as CustomEvent;
      if (onAction) {
        onAction(customEvent.detail.name);
      }
    };

    el.addEventListener('oim:action', handleAction);
    return () => el.removeEventListener('oim:action', handleAction);
  }, [onAction]);

  return (
    <div className="w-full max-w-2xl mx-auto">
      {/* @ts-expect-error custom-element */}
      <oim-player ref={playerRef} src={src} lang={lang} fit="contain" />
    </div>
  );
}

2. Vue 3 (Composition API / Nuxt 3) ​

Vue handles custom elements natively. Ensure your compiler options recognize oim- tags:

vue
<template>
  <div class="player-container">
    <oim-player
      ref="playerRef"
      :src="src"
      :lang="activeLang"
      fit="contain"
      @oim:action="handleAction"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import '@oim-media/player-oim';

const props = defineProps<{ src: string }>();
const activeLang = ref('en');
const playerRef = ref<HTMLElement | null>(null);

const handleAction = (e: CustomEvent) => {
  console.log('Action selected:', e.detail.name);
};
</script>

3. Svelte 5 & SvelteKit ​

Dynamic client import ensures server-side rendering (SSR) does not attempt to evaluate custom element definitions:

svelte
<script lang="ts">
  import { onMount } from 'svelte';

  export let src: string;
  export let lang: string = 'en';

  onMount(async () => {
    await import('@oim-media/player-oim');
  });
</script>

<div class="oim-wrapper">
  <oim-player {src} {lang} fit="contain"></oim-player>
</div>

<style>
  .oim-wrapper {
    width: 100%;
    aspect-ratio: 16 / 9;
  }
</style>

4. Astro (Island Architecture) ​

In Astro, <script> tags run exclusively on the client, providing zero hydration cost:

astro
---
interface Props {
  src: string;
  lang?: string;
}

const { src, lang = 'en' } = Astro.props;
---

<div class="interactive-card">
  <oim-player src={src} lang={lang} fit="contain"></oim-player>
</div>

<script>
  import '@oim-media/player-oim';
</script>

5. Vanilla JavaScript & HTML5 ​

No bundler or build step is required for standard web pages:

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <script type="module" src="https://cdn.oim.media/player/v1/oim-player.js"></script>
</head>
<body>
  <oim-player
    id="myPromo"
    src="/media/hero.oim.png"
    lang="en"
    fit="cover">
  </oim-player>

  <script>
    const player = document.getElementById('myPromo');
    player.addEventListener('oim:loaded', () => {
      console.log('OIM Ready!');
    });
  </script>
</body>
</html>