openclaw-webchat-vue
v0.2.0
Published
Vue components and composables for OpenClaw WebChat
Readme
openclaw-webchat-vue
Vue 3 composables and components for OpenClaw Gateway. Build AI chat interfaces with ease.
Installation
npm install openclaw-webchat-vue
# or
pnpm add openclaw-webchat-vue
# or
yarn add openclaw-webchat-vueQuick Start
Using ChatWidget (Easiest)
Drop-in chat widget with built-in UI:
<script setup>
import { ChatWidget } from 'openclaw-webchat-vue';
import 'openclaw-webchat-vue/style.css'; // Required for styles
</script>
<template>
<ChatWidget
gateway="wss://your-gateway.example.com/ws"
token="your-auth-token"
position="bottom-right"
theme="light"
title="AI Assistant"
/>
</template>Important: You must import the CSS file for styles to work.
Using Composable (Custom UI)
Build your own chat interface:
<script setup>
import { ref } from 'vue';
import { useOpenClawChat } from 'openclaw-webchat-vue';
const {
messages,
isConnected,
isLoading,
streamingContent,
error,
send,
} = useOpenClawChat({
gateway: 'wss://your-gateway.example.com/ws',
token: 'your-auth-token',
});
const input = ref('');
async function handleSend() {
if (!input.value.trim() || !isConnected.value) return;
await send(input.value);
input.value = '';
}
</script>
<template>
<div class="chat">
<!-- Messages -->
<div v-for="msg in messages" :key="msg.id" :class="msg.role">
{{ msg.content }}
</div>
<!-- Streaming indicator -->
<div v-if="isLoading" class="typing">
{{ streamingContent || '...' }}
</div>
<!-- Error display -->
<div v-if="error" class="error">
{{ error.message }}
</div>
<!-- Input -->
<input
v-model="input"
@keydown.enter="handleSend"
:disabled="!isConnected || isLoading"
:placeholder="isConnected ? 'Type a message...' : 'Connecting...'"
/>
<button @click="handleSend" :disabled="!isConnected || isLoading">
Send
</button>
</div>
</template>API Reference
ChatWidget Props
interface ChatWidgetProps {
/** Gateway WebSocket URL (required) */
gateway: string;
/** Authentication token */
token?: string;
/** Authentication password (alternative to token) */
password?: string;
/** Widget position */
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'inline';
/** Color theme */
theme?: 'light' | 'dark' | 'auto';
/** Widget title */
title?: string;
/** Input placeholder text */
placeholder?: string;
/** Start with widget open (floating mode only) */
defaultOpen?: boolean;
/** Auto-connect on mount (default: true) */
autoConnect?: boolean;
/** Enable debug logging */
debug?: boolean;
// ... all OpenClawClientOptions are also supported
}ChatWidget Events
<ChatWidget
gateway="..."
token="..."
@send="(content) => console.log('Sent:', content)"
@message="(message) => console.log('Received:', message)"
/>ChatWidget Slots
<ChatWidget gateway="..." token="...">
<!-- Custom message template -->
<template #message="{ message }">
<div :class="['message', message.role]">
<strong>{{ message.role }}:</strong>
{{ message.content }}
</div>
</template>
<!-- Custom loading template -->
<template #loading="{ content }">
<div class="loading">
AI is typing: {{ content }}
</div>
</template>
</ChatWidget>useOpenClawChat Composable
const {
messages, // Ref<Message[]> - all messages
connectionState, // Ref<ConnectionState> - current connection state
isConnected, // ComputedRef<boolean> - is connected
isLoading, // Ref<boolean> - is sending/receiving
streamingContent, // Ref<string> - current streaming content
error, // Ref<Error | null> - last error
send, // (content: string) => Promise<void>
connect, // () => Promise<void>
disconnect, // () => void
clearMessages, // () => void
loadHistory, // (limit?: number) => Promise<void>
client, // Ref<OpenClawClient | null> - underlying client
} = useOpenClawChat(options);Composable Options
interface UseOpenClawChatOptions {
/** Gateway WebSocket URL (required) */
gateway: string;
/** Authentication token */
token?: string;
/** Auto-connect on mount (default: true) */
autoConnect?: boolean;
// ... all OpenClawClientOptions are also supported
}Examples
Inline Chat
<ChatWidget
gateway="wss://your-gateway.example.com/ws"
token="your-token"
position="inline"
theme="light"
/>Dark Mode
<ChatWidget
gateway="wss://your-gateway.example.com/ws"
token="your-token"
theme="dark"
/>
<!-- Or auto-detect system preference -->
<ChatWidget
gateway="wss://your-gateway.example.com/ws"
token="your-token"
theme="auto"
/>Custom Positioning
<ChatWidget
gateway="wss://your-gateway.example.com/ws"
token="your-token"
position="bottom-left"
/>With Manual Connection
<script setup>
import { useOpenClawChat } from 'openclaw-webchat-vue';
const { isConnected, connect, disconnect } = useOpenClawChat({
gateway: 'wss://your-gateway.example.com/ws',
token: 'your-token',
autoConnect: false, // Don't connect automatically
});
</script>
<template>
<button v-if="isConnected" @click="disconnect">Disconnect</button>
<button v-else @click="connect">Connect</button>
</template>Reactive Gateway URL
<script setup>
import { ref, watch } from 'vue';
import { useOpenClawChat } from 'openclaw-webchat-vue';
const gateway = ref('wss://gateway1.example.com/ws');
const chat = useOpenClawChat({
gateway: gateway.value,
token: 'your-token',
});
// Note: To switch gateways, you'll need to create a new composable instance
// or manually disconnect and reconnect
</script>TypeScript
Full TypeScript support with exported types:
import type {
OpenClawClientOptions,
Message,
ConnectionState,
} from 'openclaw-webchat-vue';CSS Import
The ChatWidget component uses scoped CSS. You must import the styles:
// Option 1: In your main entry file
import 'openclaw-webchat-vue/style.css';
// Option 2: In your component
import 'openclaw-webchat-vue/dist/index.css';If styles are not showing, make sure you've imported the CSS file.
License
MIT
