React
Prerequisites
1. Add SDK Script
Add the SDK script inside the <head>
tag of your public/index.html
file.
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
{/* ... other meta tags and links ... */}
<title>React + Klleon Chat SDK</title>
{/* TODO: Replace {VERSION} with the actual SDK version (e.g., 1.2.0) */}
<script src="https://web.sdk.klleon.io/{VERSION}/klleon-chat.umd.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
2. TypeScript Type Support (Optional)
Klleon Chat SDK provides TypeScript declaration files. If you include these .d.ts
files in your project, you can benefit from full type safety and autocomplete for window.KlleonChat
, SDK methods, and web component props.
React Example (App.tsx
)
CSS Styles
custom.css
.base-react-example-page {
width: 100%;
height: 100%;
.header {
margin-bottom: 30px;
}
.loading-text {
position: absolute;
font-size: 1.5em;
color: #555;
padding: 50px;
}
.start-chat-button {
width: 150px;
height: 50px;
background-color: #0c5ef0;
color: #fff;
border-radius: 10px;
font-size: 16px;
font-weight: 600;
border: none;
cursor: pointer;
}
.sdk-container {
display: flex;
width: 100%;
height: 720px;
gap: 0px 24px;
.avatar-container {
flex: 1;
}
.chat-control-container {
display: flex;
flex-direction: column;
flex: 1;
gap: 24px 0px;
.chat-container {
flex: 1;
border-radius: 24px;
}
.chat-echo-container {
display: flex;
flex-direction: column;
.echo-input {
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0 10px;
font-size: 16px;
margin-bottom: 10px;
}
.echo-button {
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0 10px;
background-color: #0c5ef0;
color: #fff;
font-size: 16px;
font-weight: 600;
cursor: pointer;
&:disabled {
background-color: #ccc;
color: #fff;
cursor: not-allowed;
}
}
}
}
}
}
src/App.tsx
import { ChatData, Status } from "@site/src/types/global";
import { useEffect, useRef, useState, CSSProperties } from "react";
// TODO: Replace with your actual SDK key and Avatar ID
const SDK_KEY = "YOUR_SDK_KEY";
const AVATAR_ID = "YOUR_AVATAR_ID";
interface AvatarProps {
videoStyle?: CSSProperties;
volume?: number;
}
interface ChatProps {
delay?: number;
type?: "voice" | "text";
isShowCount?: boolean;
}
function App() {
const [echoText, setEchoText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isChatStarted, setIsChatStarted] = useState(false);
const avatarContainerRef = useRef<HTMLElement & AvatarProps>(null);
const chatContainerRef = useRef<HTMLElement & ChatProps>(null);
useEffect(() => {
if (avatarContainerRef.current) {
avatarContainerRef.current.videoStyle = {
borderRadius: "24px",
objectFit: "cover",
};
avatarContainerRef.current.volume = 100;
}
if (chatContainerRef.current) {
chatContainerRef.current.delay = 10;
chatContainerRef.current.type = "text";
chatContainerRef.current.isShowCount = true;
console.log("chat-container props set via ref.");
}
}, []);
const startChat = async () => {
setIsChatStarted(true);
const KlleonChat = window.KlleonChat;
console.log("SDK detected. Attempting initialization...");
KlleonChat.onStatusEvent((status: Status) => {
console.log(`SDK Status Event: ${status}`);
setIsLoading(status !== "VIDEO_CAN_PLAY");
});
KlleonChat.onChatEvent((chatData: ChatData) => {
console.log("SDK Chat Event:", chatData);
});
try {
await KlleonChat.init({
sdk_key: SDK_KEY,
avatar_id: AVATAR_ID,
log_level: "debug",
});
console.log("SDK initialized successfully!");
} catch (error) {
console.error(
`SDK initialization failed: ${(error as Error).message || error}`
);
setIsLoading(false);
} finally {
setIsLoading(false);
}
};
const handleEcho = () => {
window.KlleonChat.echo(echoText);
setEchoText("");
};
return (
<div className="base-react-example-page">
{!isChatStarted && (
<button
onClick={startChat}
disabled={isLoading}
className="start-chat-button"
>
Start Chat
</button>
)}
<div className="sdk-container">
{isLoading && (
<span className="loading-text">Klleon Avatar Loading...</span>
)}
<avatar-container ref={avatarContainerRef} class="avatar-container" />
<div className="chat-control-container">
<chat-container ref={chatContainerRef} class="chat-container" />
<div className="chat-echo-container">
<input
type="text"
value={echoText}
onChange={(e) => setEchoText(e.target.value)}
placeholder="Enter echo text..."
disabled={isLoading}
className="echo-input"
/>
<button
onClick={handleEcho}
disabled={isLoading}
className="echo-button"
>
Send echo
</button>
</div>
</div>
</div>
</div>
);
}
export default App;