Vue.js Integration

Integrate BotHarbor chat widget into your Vue.js applications with support for both Vue 2 and Vue 3.

Vue 3 Composition API

The recommended approach for Vue 3 applications using the modern Composition API.

Basic Setup

<template>
  <div class="app">
    <header>
      <h1>My Vue App</h1>
      <button @click="openChat" class="chat-button">
        Need Help?
      </button>
    </header>
    <main>
      <p>Your app content here...</p>
    </main>
  </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref } from 'vue'

const chatReady = ref(false)

const loadBotHarbor = () => {
  return new Promise((resolve, reject) => {
    if (window.BotHarbor) {
      resolve(window.BotHarbor)
      return
    }

    const script = document.createElement('script')
    script.src = 'https://botharbor.ai/embed.js'
    script.async = true
    script.onload = () => resolve(window.BotHarbor)
    script.onerror = reject
    document.head.appendChild(script)
  })
}

const initializeBotHarbor = async () => {
  try {
    const BotHarbor = await loadBotHarbor()
    BotHarbor.init({
      botId: import.meta.env.VITE_BOTHARBOR_BOT_ID,
      theme: 'light',
      position: 'bottom-right',
      autoOpen: false,
      onReady: () => {
        chatReady.value = true
        console.log('BotHarbor is ready')
      }
    })
  } catch (error) {
    console.error('Failed to load BotHarbor:', error)
  }
}

const openChat = () => {
  if (window.BotHarbor && chatReady.value) {
    window.BotHarbor.open()
  }
}

const closeChat = () => {
  if (window.BotHarbor) {
    window.BotHarbor.close()
  }
}

onMounted(() => {
  initializeBotHarbor()
})

onUnmounted(() => {
  if (window.BotHarbor) {
    window.BotHarbor.destroy()
  }
})
</script>

Vue 3 Composable

Create a reusable composable for better organization and reusability across components.

useBotHarbor Composable

// composables/useBotHarbor.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useBotHarbor(config = {}) {
  const isReady = ref(false)
  const isOpen = ref(false)
  const error = ref(null)

  const defaultConfig = {
    theme: 'light',
    position: 'bottom-right',
    autoOpen: false,
    ...config
  }

  const loadScript = () => {
    return new Promise((resolve, reject) => {
      if (window.BotHarbor) {
        resolve(window.BotHarbor)
        return
      }

      const script = document.createElement('script')
      script.src = 'https://botharbor.ai/embed.js'
      script.async = true
      script.onload = () => resolve(window.BotHarbor)
      script.onerror = () => reject(new Error('Failed to load BotHarbor script'))
      document.head.appendChild(script)
    })
  }

  const initialize = async () => {
    try {
      const BotHarbor = await loadScript()
      BotHarbor.init({
        ...defaultConfig,
        onReady: () => {
          isReady.value = true
          defaultConfig.onReady?.()
        },
        onOpen: () => {
          isOpen.value = true
          defaultConfig.onOpen?.()
        },
        onClose: () => {
          isOpen.value = false
          defaultConfig.onClose?.()
        },
        onError: (err) => {
          error.value = err
          defaultConfig.onError?.(err)
        }
      })
    } catch (err) {
      error.value = err
      console.error('BotHarbor initialization failed:', err)
    }
  }

  const open = () => {
    if (window.BotHarbor && isReady.value) {
      window.BotHarbor.open()
    }
  }

  const close = () => {
    if (window.BotHarbor) {
      window.BotHarbor.close()
    }
  }

  const sendMessage = (message) => {
    if (window.BotHarbor && isReady.value) {
      window.BotHarbor.sendMessage(message)
    }
  }

  const setUser = (user) => {
    if (window.BotHarbor && isReady.value) {
      window.BotHarbor.setUser(user)
    }
  }

  onMounted(() => {
    initialize()
  })

  onUnmounted(() => {
    if (window.BotHarbor) {
      window.BotHarbor.destroy()
    }
  })

  return {
    isReady,
    isOpen,
    error,
    open,
    close,
    sendMessage,
    setUser
  }
}

Using the Composable

<template>
  <div class="app">
    <header>
      <h1>My Vue App</h1>
      <div class="chat-controls">
        <button 
          @click="open" 
          :disabled="!isReady"
          class="btn btn-primary"
        >
          {{ isReady ? 'Open Chat' : 'Loading...' }}
        </button>
        <button 
          @click="close" 
          :disabled="!isOpen"
          class="btn btn-secondary"
        >
          Close Chat
        </button>
      </div>
      <div v-if="error" class="error">
        Error: {{ error.message }}
      </div>
    </header>
    <main>
      <p>Chat status: {{ isOpen ? 'Open' : 'Closed' }}</p>
    </main>
  </div>
</template>

<script setup>
import { useBotHarbor } from '@/composables/useBotHarbor'

const { isReady, isOpen, error, open, close, sendMessage, setUser } = useBotHarbor({
  botId: import.meta.env.VITE_BOTHARBOR_BOT_ID,
  theme: 'auto',
  position: 'bottom-right',
  onReady: () => {
    console.log('Chat is ready!')
    // Set user information when chat is ready
    setUser({
      name: 'John Doe',
      email: 'john@example.com'
    })
  }
})
</script>

Vue 2 Options API

For Vue 2 applications using the traditional Options API approach.

<template>
  <div class="app">
    <header>
      <h1>My Vue 2 App</h1>
      <button @click="openChat" :disabled="!chatReady">
        {{ chatReady ? 'Open Chat' : 'Loading Chat...' }}
      </button>
    </header>
    <main>
      <p>Your app content here...</p>
    </main>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      chatReady: false,
      chatOpen: false
    }
  },
  async mounted() {
    await this.initializeBotHarbor()
  },
  beforeDestroy() {
    if (window.BotHarbor) {
      window.BotHarbor.destroy()
    }
  },
  methods: {
    loadBotHarborScript() {
      return new Promise((resolve, reject) => {
        if (window.BotHarbor) {
          resolve(window.BotHarbor)
          return
        }

        const script = document.createElement('script')
        script.src = 'https://botharbor.ai/embed.js'
        script.async = true
        script.onload = () => resolve(window.BotHarbor)
        script.onerror = reject
        document.head.appendChild(script)
      })
    },
    async initializeBotHarbor() {
      try {
        const BotHarbor = await this.loadBotHarborScript()
        BotHarbor.init({
          botId: process.env.VUE_APP_BOTHARBOR_BOT_ID,
          theme: 'light',
          position: 'bottom-right',
          autoOpen: false,
          onReady: () => {
            this.chatReady = true
            console.log('BotHarbor is ready')
          },
          onOpen: () => {
            this.chatOpen = true
          },
          onClose: () => {
            this.chatOpen = false
          }
        })
      } catch (error) {
        console.error('Failed to initialize BotHarbor:', error)
      }
    },
    openChat() {
      if (window.BotHarbor && this.chatReady) {
        window.BotHarbor.open()
      }
    },
    closeChat() {
      if (window.BotHarbor) {
        window.BotHarbor.close()
      }
    }
  }
}
</script>

Environment Configuration

Configure your Vue application with environment variables for different deployment environments.

Environment Files

# .env.local (Vue 3 with Vite)
VITE_BOTHARBOR_BOT_ID=your-bot-id-here
VITE_BOTHARBOR_THEME=light
VITE_BOTHARBOR_POSITION=bottom-right

# .env.local (Vue 2 with Vue CLI)
VUE_APP_BOTHARBOR_BOT_ID=your-bot-id-here
VUE_APP_BOTHARBOR_THEME=light
VUE_APP_BOTHARBOR_POSITION=bottom-right

Best Practices

Performance Optimization

  • Use async script loading to prevent blocking
  • Initialize BotHarbor in mounted/onMounted lifecycle
  • Clean up resources in beforeDestroy/onUnmounted
  • Use composables for reusable logic (Vue 3)