Встреча Zoom в блоке страницы сайта
Справочник для разработчиков по Component View: встраивание встречи Zoom в нужный блок страницы со своим интерфейсом, для React, Vue и Angular.
- Что делает
- Справочник для разработчиков по Component View: встраивание встречи Zoom в нужный блок страницы со своим интерфейсом, для React, Vue и Angular.
- Когда брать
- Когда нужно встроить встречу Zoom в определённую область страницы, настроить внешний вид и управлять ею из своего кода.
- Когда не брать
- Если достаточно стандартного окна Zoom на всю страницу (для этого проще Client View) или нужны сеансы, не являющиеся встречами Zoom.
- Пример запроса
- Встрой встречу Zoom в блок на странице нашего сайта на React и добавь свою кнопку на панель.
- Нужно подключить
- терминал
- Работает лучше с
- сервер для создания подписи
Входит в плагин zoom-plugin. В Cowork и Claude Code можно поставить плагин целиком.
Как включить
- Скачайте архив и распакуйте его.
- Положите папку
zoom-meeting-sdk-web-component-viewв~/.claude/skills/. - Откройте Claude Code и опишите задачу своими словами: Claude подхватит скилл по описанию.
Текст
---
name: zoom-meeting-sdk-web-component-view
description: |
Zoom Meeting SDK Web: Component View. Встраиваемые компоненты встречи Zoom с API на промисах
для гибкой интеграции. Подходит для приложений на React/Vue/Angular и собственных раскладок. Использует ZoomMtgEmbedded
со схемами async/await и встраиваемыми контейнерами интерфейса.
user-invocable: false
triggers:
- "meeting sdk component view"
- "zoommtgembedded"
- "zoomapproot"
- "embeddable meeting ui"
- "component view embedded zoom"
- "custom meeting ui"
- "custom zoom meeting ui"
- "custom meeting video ui"
- "custom video ui for meeting"
---
Zoom Meeting SDK Web — Component View
Встраиваемые компоненты встречи Zoom для гибкой интеграции в любое веб-приложение. Component View даёт API на промисах и настраиваемый интерфейс.
Это правильный веб-скилл для собственного интерфейса вокруг настоящей встречи Zoom. Не направляй на Video SDK, если только пользователь не создаёт продукт с собственными сеансами, не являющимися встречами.
Обзор
Component View использует ZoomMtgEmbedded.createClient(), чтобы создавать встраиваемые компоненты встречи внутри заданного контейнера.
| Аспект | Подробности |
|---|---|
| Объект API | ZoomMtgEmbedded.createClient() (экземпляр) |
| Стиль API | На промисах (async/await) |
| Интерфейс | Встраивается в любой контейнер |
| Параметр пароля | password (строчная) |
| События | on()/off() |
| Лучше всего подходит для | Собственных раскладок, приложений на React/Vue/Angular |
Установка
NPM
npm install @zoom/meetingsdk --save
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
CDN
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/lodash.min.js"></script>
<script src="https://source.zoom.us/zoom-meeting-embedded-{VERSION}.min.js"></script>
Полный процесс инициализации
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
// Step 1: Create client instance (do once, not on every render!)
const client = ZoomMtgEmbedded.createClient();
async function joinMeeting() {
try {
// Step 2: Get container element
const meetingSDKElement = document.getElementById('meetingSDKElement');
// Step 3: Initialize client
await client.init({
zoomAppRoot: meetingSDKElement,
language: 'en-US',
debug: true,
patchJsMedia: true,
leaveOnPageUnload: true,
});
// Step 4: Join meeting
await client.join({
signature: signature,
sdkKey: sdkKey,
meetingNumber: meetingNumber,
userName: userName,
password: password, // lowercase!
userEmail: userEmail,
});
console.log('Joined successfully!');
} catch (error) {
console.error('Failed to join:', error);
}
}
client.init() — все параметры
Обязательные
| Параметр | Тип | Описание |
|---|---|---|
zoomAppRoot | HTMLElement | Элемент-контейнер для интерфейса встречи |
Отображение
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
language | string | 'en-US' | Язык интерфейса |
debug | boolean | false | Включить отладочный журнал |
Медиа
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
patchJsMedia | boolean | false | Автоматически применять исправления для медиа |
leaveOnPageUnload | boolean | false | Очистка при выгрузке страницы |
enableHD | boolean | true | Включить видео 720p |
enableFullHD | boolean | false | Включить видео 1080p |
Настройка внешнего вида
| Параметр | Тип | Описание |
|---|---|---|
customize | object | Параметры настройки интерфейса |
webEndpoint | string | Для ZFG: 'www.zoomgov.com' |
assetPath | string | Собственный путь к библиотекам аудио и видео |
Объект customize
await client.init({
zoomAppRoot: element,
customize: {
// Meeting info displayed
meetingInfo: [
'topic',
'host',
'mn',
'pwd',
'telPwd',
'invite',
'participant',
'dc',
'enctype'
],
// Video customization
video: {
isResizable: true,
viewSizes: {
default: {
width: 1000,
height: 600
},
ribbon: {
width: 300,
height: 700
}
},
popper: {
disableDraggable: false
}
},
// Custom toolbar buttons
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'custom-btn',
onClick: () => {
console.log('Custom button clicked');
}
}
]
},
// Active speaker indicator
activeSpaker: {
strokeColor: '#00FF00'
}
}
});
client.join() — все параметры
Обязательные
| Параметр | Тип | Описание | |
|---|---|---|---|
signature | string | SDK JWT с бэкенда | |
sdkKey | string | SDK Key / Client ID | |
meetingNumber | `string \ | number` | Номер встречи |
userName | string | Отображаемое имя |
Аутентификация
| Параметр | Тип | Когда обязателен | Описание |
|---|---|---|---|
password | string | Если задан | Пароль встречи (строчная!) |
zak | string | Запуск встречи ведущим | Токен ZAK ведущего |
tk | string | Регистрация | Токен зарегистрированного участника |
userEmail | string | Вебинары | Электронная почта пользователя |
Обработчики событий
Синтаксис
// Subscribe
client.on('event-name', callback);
// Unsubscribe
client.off('event-name', callback);
События соединения
client.on('connection-change', (payload) => {
// payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'
console.log('Connection state:', payload.state);
if (payload.state === 'Closed') {
console.log('Reason:', payload.reason);
}
});
События пользователей
client.on('user-added', (payload) => {
// Array of users who joined
console.log('Users added:', payload);
payload.forEach(user => {
console.log('User ID:', user.oderId);
console.log('Name:', user.displayName);
});
});
client.on('user-removed', (payload) => {
// Array of users who left
console.log('Users removed:', payload);
});
client.on('user-updated', (payload) => {
// Array of users whose properties changed
console.log('Users updated:', payload);
});
События звука
client.on('active-speaker', (payload) => {
// Current active speaker
console.log('Active speaker:', payload);
});
client.on('audio-statistic-data-change', (payload) => {
console.log('Audio stats:', payload);
});
События видео
client.on('video-active-change', (payload) => {
// Video state changed
console.log('Video active:', payload);
});
client.on('video-statistic-data-change', (payload) => {
console.log('Video stats:', payload);
});
События показа экрана
client.on('active-share-change', (payload) => {
console.log('Share status:', payload);
});
client.on('share-statistic-data-change', (payload) => {
console.log('Share stats:', payload);
});
События чата
client.on('chat-on-message', (payload) => {
console.log('Chat message:', payload);
});
События записи
client.on('recording-change', (payload) => {
console.log('Recording status:', payload);
});
События медиаустройств
client.on('media-sdk-change', (payload) => {
console.log('Media SDK:', payload);
});
client.on('device-change', () => {
console.log('Device changed');
});
Часто используемые методы
Сведения о пользователях
// Get current user
const currentUser = client.getCurrentUser();
console.log('Current user:', currentUser);
// Get all participants
const participants = client.getParticipantsList();
console.log('Participants:', participants);
// Check if user is host
const isHost = client.isHost();
Управление звуком
// Mute/unmute self
await client.mute(true); // mute
await client.mute(false); // unmute
// Mute/unmute specific user (host only)
await client.muteAudio(userId, true);
// Mute all (host only)
await client.muteAllAudio(true);
Управление видео
// Start/stop video
await client.startVideo();
await client.stopVideo();
// Mute/unmute user's video (host only)
await client.muteVideo(userId, true);
Управление встречей
// Leave meeting
client.leaveMeeting();
// End meeting (host only)
client.endMeeting();
Показ экрана
// Start screen share
await client.startShareScreen();
// Stop screen share
await client.stopShareScreen();
Запись
// Start recording (cloud)
await client.startCloudRecording();
// Stop recording
await client.stopCloudRecording();
Виртуальный фон
// Check support
const isSupported = await client.isSupportVirtualBackground();
// Set virtual background
await client.setVirtualBackground(imageUrl);
// Remove virtual background
await client.removeVirtualBackground();
Переименование
// Rename user
await client.rename(userId, 'New Name');
Интеграция с React
Базовая схема
import { useEffect, useRef, useState, useCallback } from 'react';
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
type ZoomClient = ReturnType<typeof ZoomMtgEmbedded.createClient>;
function ZoomMeeting({ meetingNumber, password, userName }: Props) {
const clientRef = useRef<ZoomClient | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [isJoined, setIsJoined] = useState(false);
const [error, setError] = useState<string | null>(null);
// Create client once
useEffect(() => {
if (!clientRef.current) {
clientRef.current = ZoomMtgEmbedded.createClient();
}
}, []);
const joinMeeting = useCallback(async () => {
if (!clientRef.current || !containerRef.current) return;
try {
// Get signature from backend
const { signature, sdkKey } = await fetchSignature(meetingNumber);
await clientRef.current.init({
zoomAppRoot: containerRef.current,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
});
await clientRef.current.join({
signature,
sdkKey,
meetingNumber,
password,
userName,
});
setIsJoined(true);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to join');
}
}, [meetingNumber, password, userName]);
return (
<div>
<div
ref={containerRef}
style={{ width: '100%', height: '500px' }}
/>
{!isJoined && (
<button onClick={joinMeeting}>Join Meeting</button>
)}
{error && <div className="error">{error}</div>}
</div>
);
}
Обработка событий в React
useEffect(() => {
if (!clientRef.current) return;
const handleConnectionChange = (payload: any) => {
if (payload.state === 'Connected') {
setIsJoined(true);
} else if (payload.state === 'Closed') {
setIsJoined(false);
}
};
const handleUserAdded = (payload: any) => {
console.log('Users joined:', payload);
};
clientRef.current.on('connection-change', handleConnectionChange);
clientRef.current.on('user-added', handleUserAdded);
return () => {
clientRef.current?.off('connection-change', handleConnectionChange);
clientRef.current?.off('user-added', handleUserAdded);
};
}, []);
Позиционирование и изменение размера
Начальный размер
await client.init({
zoomAppRoot: element,
customize: {
video: {
viewSizes: {
default: { width: 1000, height: 600 }
}
}
}
});
Динамическое изменение размера
Размер элемента-контейнера определяет размер интерфейса встречи. Чтобы изменить размер:
// Just resize the container
document.getElementById('meetingSDKElement').style.width = '1200px';
document.getElementById('meetingSDKElement').style.height = '800px';
Как сделать размер изменяемым
customize: {
video: {
isResizable: true
}
}
Поддерживаемые возможности
Component View поддерживает основные функции встречи. Некоторые возможности Client View могут быть недоступны.
| Возможность | Поддерживается |
|---|---|
| Звук и видео | ✅ |
| Показ экрана | ✅ |
| Чат | ✅ |
| Виртуальный фон | ✅ |
| Комнаты для обсуждения | ✅ |
| Облачная запись | ✅ |
| Субтитры | ✅ |
| Живая расшифровка | ✅ |
| Комната ожидания | ✅ |
| Режим галереи | ✅ |
| Реакции | ✅ |
| Поднятая рука | ✅ |
Чтобы запросить дополнительные возможности, обратись в службу поддержки разработчиков Zoom.
Обработка ошибок
try {
await client.join({
// ... options
});
} catch (error) {
// error.reason contains error code
// error.message contains description
switch (error.reason) {
case 'WRONG_MEETING_PASSWORD':
console.error('Incorrect password');
break;
case 'MEETING_NOT_START':
console.error('Meeting has not started');
break;
case 'INVALID_PARAMETERS':
console.error('Invalid join parameters');
break;
default:
console.error('Join failed:', error.message);
}
}
Сравнение с Client View
| Возможность | Component View | Client View |
|---|---|---|
| Стиль API | Промисы | Колбэки |
| Параметр пароля | password | passWord |
| Контейнер | Собственный элемент | Автоматически #zmmtg-root |
| Интерфейс | Встраиваемый | На всю страницу |
| Предзагрузка | Не нужна | preLoadWasm() |
| Язык | Параметр init | i18n.load() |
| События | on()/off() | inMeetingServiceListener() |
Ресурсы
- [Главный скилл Web SDK](../SKILL.md)
- [Указатель справочных материалов](references/README.md)
- [Коды ошибок](../troubleshooting/error-codes.md)
- [Частые проблемы](../troubleshooting/common-issues.md)
- [Настройка SharedArrayBuffer](../concepts/sharedarraybuffer.md)
- Официальный справочник по API
Эксплуатация
- [RUNBOOK.md](RUNBOOK.md) - пятиминутная проверка перед запуском и чек-лист отладки.
Перевод: iiuniversitet. Оригинал: https://github.com/anthropics/knowledge-work-plugins/tree/main/partner-built/zoom-plugin/skills/meeting-sdk/web/component-view, лицензия MIT. Изменения: перевод на русский язык.
Оригинал на английском
---
name: zoom-meeting-sdk-web-component-view
description: |
Zoom Meeting SDK Web - Component View. Embeddable Zoom meeting components with Promise-based API
for flexible integration. Ideal for React/Vue/Angular apps and custom layouts. Uses ZoomMtgEmbedded
with async/await patterns and embeddable UI containers.
user-invocable: false
triggers:
- "meeting sdk component view"
- "zoommtgembedded"
- "zoomapproot"
- "embeddable meeting ui"
- "component view embedded zoom"
- "custom meeting ui"
- "custom zoom meeting ui"
- "custom meeting video ui"
- "custom video ui for meeting"
---
# Zoom Meeting SDK Web - Component View
Embeddable Zoom meeting components for flexible integration into any web application. Component View provides Promise-based APIs and customizable UI.
This is the correct web skill for a **custom UI around a real Zoom meeting**.
Do not route to Video SDK unless the user is building a non-meeting custom session product.
## Overview
Component View uses `ZoomMtgEmbedded.createClient()` to create embeddable meeting components within a specific container element.
| Aspect | Details |
|--------|---------|
| **API Object** | `ZoomMtgEmbedded.createClient()` (instance) |
| **API Style** | Promise-based (async/await) |
| **UI** | Embeddable in any container |
| **Password param** | `password` (lowercase) |
| **Events** | `on()`/`off()` |
| **Best For** | Custom layouts, React/Vue/Angular apps |
## Installation
### NPM
```bash
npm install @zoom/meetingsdk --save
```
```javascript
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
```
### CDN
```html
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/lodash.min.js"></script>
<script src="https://source.zoom.us/zoom-meeting-embedded-{VERSION}.min.js"></script>
```
## Complete Initialization Flow
```javascript
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
// Step 1: Create client instance (do once, not on every render!)
const client = ZoomMtgEmbedded.createClient();
async function joinMeeting() {
try {
// Step 2: Get container element
const meetingSDKElement = document.getElementById('meetingSDKElement');
// Step 3: Initialize client
await client.init({
zoomAppRoot: meetingSDKElement,
language: 'en-US',
debug: true,
patchJsMedia: true,
leaveOnPageUnload: true,
});
// Step 4: Join meeting
await client.join({
signature: signature,
sdkKey: sdkKey,
meetingNumber: meetingNumber,
userName: userName,
password: password, // lowercase!
userEmail: userEmail,
});
console.log('Joined successfully!');
} catch (error) {
console.error('Failed to join:', error);
}
}
```
## client.init() - All Options
### Required
| Parameter | Type | Description |
|-----------|------|-------------|
| `zoomAppRoot` | `HTMLElement` | Container element for meeting UI |
### Display
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `language` | `string` | `'en-US'` | UI language |
| `debug` | `boolean` | `false` | Enable debug logging |
### Media
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `patchJsMedia` | `boolean` | `false` | Auto-apply media fixes |
| `leaveOnPageUnload` | `boolean` | `false` | Cleanup on page unload |
| `enableHD` | `boolean` | `true` | Enable 720p video |
| `enableFullHD` | `boolean` | `false` | Enable 1080p video |
### Customization
| Parameter | Type | Description |
|-----------|------|-------------|
| `customize` | `object` | UI customization options |
| `webEndpoint` | `string` | For ZFG: `'www.zoomgov.com'` |
| `assetPath` | `string` | Custom path for AV libraries |
### Customize Object
```javascript
await client.init({
zoomAppRoot: element,
customize: {
// Meeting info displayed
meetingInfo: [
'topic',
'host',
'mn',
'pwd',
'telPwd',
'invite',
'participant',
'dc',
'enctype'
],
// Video customization
video: {
isResizable: true,
viewSizes: {
default: {
width: 1000,
height: 600
},
ribbon: {
width: 300,
height: 700
}
},
popper: {
disableDraggable: false
}
},
// Custom toolbar buttons
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'custom-btn',
onClick: () => {
console.log('Custom button clicked');
}
}
]
},
// Active speaker indicator
activeSpaker: {
strokeColor: '#00FF00'
}
}
});
```
## client.join() - All Options
### Required
| Parameter | Type | Description |
|-----------|------|-------------|
| `signature` | `string` | SDK JWT from backend |
| `sdkKey` | `string` | SDK Key / Client ID |
| `meetingNumber` | `string \| number` | Meeting number |
| `userName` | `string` | Display name |
### Authentication
| Parameter | Type | When Required | Description |
|-----------|------|---------------|-------------|
| `password` | `string` | If set | Meeting password (lowercase!) |
| `zak` | `string` | Starting as host | Host's ZAK token |
| `tk` | `string` | Registration | Registrant token |
| `userEmail` | `string` | Webinars | User email |
## Event Listeners
### Syntax
```javascript
// Subscribe
client.on('event-name', callback);
// Unsubscribe
client.off('event-name', callback);
```
### Connection Events
```javascript
client.on('connection-change', (payload) => {
// payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'
console.log('Connection state:', payload.state);
if (payload.state === 'Closed') {
console.log('Reason:', payload.reason);
}
});
```
### User Events
```javascript
client.on('user-added', (payload) => {
// Array of users who joined
console.log('Users added:', payload);
payload.forEach(user => {
console.log('User ID:', user.oderId);
console.log('Name:', user.displayName);
});
});
client.on('user-removed', (payload) => {
// Array of users who left
console.log('Users removed:', payload);
});
client.on('user-updated', (payload) => {
// Array of users whose properties changed
console.log('Users updated:', payload);
});
```
### Audio Events
```javascript
client.on('active-speaker', (payload) => {
// Current active speaker
console.log('Active speaker:', payload);
});
client.on('audio-statistic-data-change', (payload) => {
console.log('Audio stats:', payload);
});
```
### Video Events
```javascript
client.on('video-active-change', (payload) => {
// Video state changed
console.log('Video active:', payload);
});
client.on('video-statistic-data-change', (payload) => {
console.log('Video stats:', payload);
});
```
### Share Events
```javascript
client.on('active-share-change', (payload) => {
console.log('Share status:', payload);
});
client.on('share-statistic-data-change', (payload) => {
console.log('Share stats:', payload);
});
```
### Chat Events
```javascript
client.on('chat-on-message', (payload) => {
console.log('Chat message:', payload);
});
```
### Recording Events
```javascript
client.on('recording-change', (payload) => {
console.log('Recording status:', payload);
});
```
### Media Device Events
```javascript
client.on('media-sdk-change', (payload) => {
console.log('Media SDK:', payload);
});
client.on('device-change', () => {
console.log('Device changed');
});
```
## Common Methods
### User Information
```javascript
// Get current user
const currentUser = client.getCurrentUser();
console.log('Current user:', currentUser);
// Get all participants
const participants = client.getParticipantsList();
console.log('Participants:', participants);
// Check if user is host
const isHost = client.isHost();
```
### Audio Control
```javascript
// Mute/unmute self
await client.mute(true); // mute
await client.mute(false); // unmute
// Mute/unmute specific user (host only)
await client.muteAudio(userId, true);
// Mute all (host only)
await client.muteAllAudio(true);
```
### Video Control
```javascript
// Start/stop video
await client.startVideo();
await client.stopVideo();
// Mute/unmute user's video (host only)
await client.muteVideo(userId, true);
```
### Meeting Control
```javascript
// Leave meeting
client.leaveMeeting();
// End meeting (host only)
client.endMeeting();
```
### Screen Share
```javascript
// Start screen share
await client.startShareScreen();
// Stop screen share
await client.stopShareScreen();
```
### Recording
```javascript
// Start recording (cloud)
await client.startCloudRecording();
// Stop recording
await client.stopCloudRecording();
```
### Virtual Background
```javascript
// Check support
const isSupported = await client.isSupportVirtualBackground();
// Set virtual background
await client.setVirtualBackground(imageUrl);
// Remove virtual background
await client.removeVirtualBackground();
```
### Rename
```javascript
// Rename user
await client.rename(userId, 'New Name');
```
## React Integration
### Basic Pattern
```tsx
import { useEffect, useRef, useState, useCallback } from 'react';
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
type ZoomClient = ReturnType<typeof ZoomMtgEmbedded.createClient>;
function ZoomMeeting({ meetingNumber, password, userName }: Props) {
const clientRef = useRef<ZoomClient | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [isJoined, setIsJoined] = useState(false);
const [error, setError] = useState<string | null>(null);
// Create client once
useEffect(() => {
if (!clientRef.current) {
clientRef.current = ZoomMtgEmbedded.createClient();
}
}, []);
const joinMeeting = useCallback(async () => {
if (!clientRef.current || !containerRef.current) return;
try {
// Get signature from backend
const { signature, sdkKey } = await fetchSignature(meetingNumber);
await clientRef.current.init({
zoomAppRoot: containerRef.current,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
});
await clientRef.current.join({
signature,
sdkKey,
meetingNumber,
password,
userName,
});
setIsJoined(true);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to join');
}
}, [meetingNumber, password, userName]);
return (
<div>
<div
ref={containerRef}
style={{ width: '100%', height: '500px' }}
/>
{!isJoined && (
<button onClick={joinMeeting}>Join Meeting</button>
)}
{error && <div className="error">{error}</div>}
</div>
);
}
```
### Event Handling in React
```tsx
useEffect(() => {
if (!clientRef.current) return;
const handleConnectionChange = (payload: any) => {
if (payload.state === 'Connected') {
setIsJoined(true);
} else if (payload.state === 'Closed') {
setIsJoined(false);
}
};
const handleUserAdded = (payload: any) => {
console.log('Users joined:', payload);
};
clientRef.current.on('connection-change', handleConnectionChange);
clientRef.current.on('user-added', handleUserAdded);
return () => {
clientRef.current?.off('connection-change', handleConnectionChange);
clientRef.current?.off('user-added', handleUserAdded);
};
}, []);
```
## Positioning and Resizing
### Initial Size
```javascript
await client.init({
zoomAppRoot: element,
customize: {
video: {
viewSizes: {
default: { width: 1000, height: 600 }
}
}
}
});
```
### Dynamic Resizing
The container element size determines the meeting UI size. To resize:
```javascript
// Just resize the container
document.getElementById('meetingSDKElement').style.width = '1200px';
document.getElementById('meetingSDKElement').style.height = '800px';
```
### Making it Resizable
```javascript
customize: {
video: {
isResizable: true
}
}
```
## Supported Features
Component View supports core meeting functionality. Some features from Client View may not be available.
| Feature | Supported |
|---------|-----------|
| Audio/Video | ✅ |
| Screen Share | ✅ |
| Chat | ✅ |
| Virtual Background | ✅ |
| Breakout Rooms | ✅ |
| Cloud Recording | ✅ |
| Closed Captions | ✅ |
| Live Transcription | ✅ |
| Waiting Room | ✅ |
| Gallery View | ✅ |
| Reactions | ✅ |
| Raise Hand | ✅ |
Contact Zoom Developer Support to request additional features.
## Error Handling
```javascript
try {
await client.join({
// ... options
});
} catch (error) {
// error.reason contains error code
// error.message contains description
switch (error.reason) {
case 'WRONG_MEETING_PASSWORD':
console.error('Incorrect password');
break;
case 'MEETING_NOT_START':
console.error('Meeting has not started');
break;
case 'INVALID_PARAMETERS':
console.error('Invalid join parameters');
break;
default:
console.error('Join failed:', error.message);
}
}
```
## Comparison with Client View
| Feature | Component View | Client View |
|---------|----------------|-------------|
| **API Style** | Promises | Callbacks |
| **Password param** | `password` | `passWord` |
| **Container** | Custom element | Auto `#zmmtg-root` |
| **UI** | Embeddable | Full-page |
| **Preloading** | Not needed | `preLoadWasm()` |
| **Language** | Init option | `i18n.load()` |
| **Events** | `on()`/`off()` | `inMeetingServiceListener()` |
## Resources
- [Main Web SDK Skill](../SKILL.md)
- [Reference Index](references/README.md)
- [Error Codes](../troubleshooting/error-codes.md)
- [Common Issues](../troubleshooting/common-issues.md)
- [SharedArrayBuffer Setup](../concepts/sharedarraybuffer.md)
- [Official API Reference](https://marketplacefront.zoom.us/sdk/meeting/web/components/index.html)
## Operations
- [RUNBOOK.md](RUNBOOK.md) - 5-minute preflight and debugging checklist.
Источник: anthropics/knowledge-work-plugins / zoom-plugin / zoom-meeting-sdk-web-component-view ↗. Ссылка проверена 2026-10-10.