Skip to content

Vite Integration

Integrate the Lingu widget into your Vite application (React, Vue, Svelte, or vanilla).

React + Vite

Using a Component

tsx
// src/components/LinguWidget.tsx
import { useEffect } from 'react';

interface LinguWidgetProps {
  apiKey: string;
  autoOpen?: boolean;
}

export function LinguWidget({ apiKey, autoOpen = false }: LinguWidgetProps) {
  useEffect(() => {
    // Set configuration
    window.linguConfig = {
      apiKey,
      autoOpen
    };

    // Load widget script
    const script = document.createElement('script');
    script.src = 'https://widget.uselingu.app/widget.js';
    script.async = true;
    script.id = 'lingu-widget-script';
    document.body.appendChild(script);

    // Cleanup on unmount
    return () => {
      const existingScript = document.getElementById('lingu-widget-script');
      if (existingScript) {
        existingScript.remove();
      }
      const container = document.getElementById('lingu-widget-root');
      if (container) {
        container.remove();
      }
    };
  }, [apiKey, autoOpen]);

  return null;
}

Usage in App

tsx
// src/App.tsx
import { LinguWidget } from './components/LinguWidget';

function App() {
  return (
    <div>
      <h1>My Vite App</h1>
      
      {/* Widget is available throughout the app */}
      <LinguWidget 
        apiKey={import.meta.env.VITE_LINGU_API_KEY}
      />
    </div>
  );
}

export default App;

Environment Variables

Create a .env file in your project root:

bash
# .env
VITE_LINGU_API_KEY=lingu_abc123def456

Access it in your code:

tsx
const apiKey = import.meta.env.VITE_LINGU_API_KEY;

TIP

Vite requires the VITE_ prefix to expose environment variables to the client.

TypeScript Support

Add type declarations for environment variables and global window:

typescript
// src/vite-env.d.ts
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_LINGU_API_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

interface Window {
  linguConfig?: {
    apiKey: string;
    autoOpen?: boolean;
    baseURL?: string;
  };
  LinguWidget?: any;
}

Vue + Vite

Using a Composable

vue
<!-- src/components/LinguWidget.vue -->
<script setup lang="ts">
import { onMounted, onBeforeUnmount } from 'vue';

const props = defineProps<{
  apiKey: string;
  autoOpen?: boolean;
}>();

onMounted(() => {
  // Set configuration
  window.linguConfig = {
    apiKey: props.apiKey,
    autoOpen: props.autoOpen ?? false
  };

  // Load widget script
  const script = document.createElement('script');
  script.src = 'https://widget.uselingu.app/widget.js';
  script.async = true;
  script.id = 'lingu-widget-script';
  document.body.appendChild(script);
});

onBeforeUnmount(() => {
  const script = document.getElementById('lingu-widget-script');
  if (script) script.remove();
  
  const container = document.getElementById('lingu-widget-root');
  if (container) container.remove();
});
</script>

<template>
  <!-- Component renders nothing, widget injects itself -->
</template>

Usage in App.vue

vue
<!-- src/App.vue -->
<script setup lang="ts">
import LinguWidget from './components/LinguWidget.vue';
</script>

<template>
  <div>
    <h1>My Vue App</h1>
    <LinguWidget :api-key="import.meta.env.VITE_LINGU_API_KEY" />
  </div>
</template>

Vanilla Vite (No Framework)

For vanilla JavaScript/TypeScript Vite projects:

html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Vite App</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
  
  <!-- Lingu Widget -->
  <script>
    window.linguConfig = {
      apiKey: 'your-api-key-here'
    };
  </script>
  <script src="https://widget.uselingu.app/widget.js" defer></script>
</body>
</html>

Dynamic Loading

Load the widget dynamically based on conditions:

typescript
// src/lib/lingu.ts
export async function loadLinguWidget(apiKey: string) {
  return new Promise<void>((resolve, reject) => {
    // Check if already loaded
    if (document.getElementById('lingu-widget-script')) {
      resolve();
      return;
    }

    // Set config
    window.linguConfig = { apiKey };

    // Load script
    const script = document.createElement('script');
    script.id = 'lingu-widget-script';
    script.src = 'https://widget.uselingu.app/widget.js';
    script.async = true;
    script.onload = () => resolve();
    script.onerror = () => reject(new Error('Failed to load Lingu widget'));
    document.body.appendChild(script);
  });
}

export function unloadLinguWidget() {
  const script = document.getElementById('lingu-widget-script');
  if (script) script.remove();
  
  const container = document.getElementById('lingu-widget-root');
  if (container) container.remove();
  
  delete window.linguConfig;
}

Usage

typescript
import { loadLinguWidget, unloadLinguWidget } from './lib/lingu';

// Load widget when user logs in
async function onLogin() {
  await loadLinguWidget(import.meta.env.VITE_LINGU_API_KEY);
}

// Unload when user logs out
function onLogout() {
  unloadLinguWidget();
}

Build Considerations

The widget loads from an external CDN, so there's no need to bundle it with your Vite build. This keeps your bundle size small and ensures you always get the latest widget version.

Powered by Lingu