[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M79ENHMMQP7GEMC9NF9DVRPB":3,"skill-same:01M79ENHMMQP7GEMC9NF9DVRPB":59},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":14,"repositoryHtmlUrl":27,"repositoryHomepageUrl":6,"ownerHtmlUrl":28,"ownerBlogUrl":6,"ownerDescription":29,"updatedAt":30,"install":31,"resources":44},"01M79ENHMMQP7GEMC9NF9DVRPB","zoom-meeting-sdk-web-component-view",null,"Zoom Meeting SDK Web - Component View. Embeddable Zoom meeting components with Promise-based API\nfor flexible integration. Ideal for React\u002FVue\u002FAngular apps and custom layouts. Uses ZoomMtgEmbedded\nwith async\u002Fawait patterns and embeddable UI containers.","zfifteen\u002Fskills-catalog","zfifteen","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F221906715?v=4","01M79CQFXDZM5J5CJTCECPFA66","Dionisio Alberto Lopez III","01M79CQFY4C62PN8A2T5KDAHGA",1,"MIT","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: zoom-meeting-sdk-web-component-view\ndescription: |\n  Zoom Meeting SDK Web - Component View. Embeddable Zoom meeting components with Promise-based API\n  for flexible integration. Ideal for React\u002FVue\u002FAngular apps and custom layouts. Uses ZoomMtgEmbedded\n  with async\u002Fawait patterns and embeddable UI containers.\n---\n\n# Zoom Meeting SDK Web - Component View\n\nEmbeddable Zoom meeting components for flexible integration into any web application. Component View provides Promise-based APIs and customizable UI.\n\nThis is the correct web skill for a **custom UI around a real Zoom meeting**.\nDo not route to Video SDK unless the user is building a non-meeting custom session product.\n\n## Overview\n\nComponent View uses `ZoomMtgEmbedded.createClient()` to create embeddable meeting components within a specific container element.\n\n| Aspect | Details |\n|--------|---------|\n| **API Object** | `ZoomMtgEmbedded.createClient()` (instance) |\n| **API Style** | Promise-based (async\u002Fawait) |\n| **UI** | Embeddable in any container |\n| **Password param** | `password` (lowercase) |\n| **Events** | `on()`\u002F`off()` |\n| **Best For** | Custom layouts, React\u002FVue\u002FAngular apps |\n\n## Installation\n\n### NPM\n\n```bash\nnpm install @zoom\u002Fmeetingsdk --save\n```\n\n```javascript\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n```\n\n### CDN\n\n```html\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Freact.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Freact-dom.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Fredux.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Fredux-thunk.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Flodash.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002Fzoom-meeting-embedded-{VERSION}.min.js\">\u003C\u002Fscript>\n```\n\n## Complete Initialization Flow\n\n```javascript\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n\n\u002F\u002F Step 1: Create client instance (do once, not on every render!)\nconst client = ZoomMtgEmbedded.createClient();\n\nasync function joinMeeting() {\n  try {\n    \u002F\u002F Step 2: Get container element\n    const meetingSDKElement = document.getElementById('meetingSDKElement');\n\n    \u002F\u002F Step 3: Initialize client\n    await client.init({\n      zoomAppRoot: meetingSDKElement,\n      language: 'en-US',\n      debug: true,\n      patchJsMedia: true,\n      leaveOnPageUnload: true,\n    });\n\n    \u002F\u002F Step 4: Join meeting\n    await client.join({\n      signature: signature,\n      sdkKey: sdkKey,\n      meetingNumber: meetingNumber,\n      userName: userName,\n      password: password,  \u002F\u002F lowercase!\n      userEmail: userEmail,\n    });\n\n    console.log('Joined successfully!');\n  } catch (error) {\n    console.error('Failed to join:', error);\n  }\n}\n```\n\n## client.init() - All Options\n\n### Required\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `zoomAppRoot` | `HTMLElement` | Container element for meeting UI |\n\n### Display\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `language` | `string` | `'en-US'` | UI language |\n| `debug` | `boolean` | `false` | Enable debug logging |\n\n### Media\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `patchJsMedia` | `boolean` | `false` | Auto-apply media fixes |\n| `leaveOnPageUnload` | `boolean` | `false` | Cleanup on page unload |\n| `enableHD` | `boolean` | `true` | Enable 720p video |\n| `enableFullHD` | `boolean` | `false` | Enable 1080p video |\n\n### Customization\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `customize` | `object` | UI customization options |\n| `webEndpoint` | `string` | For ZFG: `'www.zoomgov.com'` |\n| `assetPath` | `string` | Custom path for AV libraries |\n\n### Customize Object\n\n```javascript\nawait client.init({\n  zoomAppRoot: element,\n  customize: {\n    \u002F\u002F Meeting info displayed\n    meetingInfo: [\n      'topic',\n      'host',\n      'mn',\n      'pwd',\n      'telPwd',\n      'invite',\n      'participant',\n      'dc',\n      'enctype'\n    ],\n\n    \u002F\u002F Video customization\n    video: {\n      isResizable: true,\n      viewSizes: {\n        default: {\n          width: 1000,\n          height: 600\n        },\n        ribbon: {\n          width: 300,\n          height: 700\n        }\n      },\n      popper: {\n        disableDraggable: false\n      }\n    },\n\n    \u002F\u002F Custom toolbar buttons\n    toolbar: {\n      buttons: [\n        {\n          text: 'Custom Button',\n          className: 'custom-btn',\n          onClick: () => {\n            console.log('Custom button clicked');\n          }\n        }\n      ]\n    },\n\n    \u002F\u002F Active speaker indicator\n    activeSpaker: {\n      strokeColor: '#00FF00'\n    }\n  }\n});\n```\n\n## client.join() - All Options\n\n### Required\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `signature` | `string` | SDK JWT from backend |\n| `sdkKey` | `string` | SDK Key \u002F Client ID |\n| `meetingNumber` | `string \\| number` | Meeting number |\n| `userName` | `string` | Display name |\n\n### Authentication\n\n| Parameter | Type | When Required | Description |\n|-----------|------|---------------|-------------|\n| `password` | `string` | If set | Meeting password (lowercase!) |\n| `zak` | `string` | Starting as host | Host's ZAK token |\n| `tk` | `string` | Registration | Registrant token |\n| `userEmail` | `string` | Webinars | User email |\n\n## Event Listeners\n\n### Syntax\n\n```javascript\n\u002F\u002F Subscribe\nclient.on('event-name', callback);\n\n\u002F\u002F Unsubscribe\nclient.off('event-name', callback);\n```\n\n### Connection Events\n\n```javascript\nclient.on('connection-change', (payload) => {\n  \u002F\u002F payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'\n  console.log('Connection state:', payload.state);\n\n  if (payload.state === 'Closed') {\n    console.log('Reason:', payload.reason);\n  }\n});\n```\n\n### User Events\n\n```javascript\nclient.on('user-added', (payload) => {\n  \u002F\u002F Array of users who joined\n  console.log('Users added:', payload);\n  payload.forEach(user => {\n    console.log('User ID:', user.oderId);\n    console.log('Name:', user.displayName);\n  });\n});\n\nclient.on('user-removed', (payload) => {\n  \u002F\u002F Array of users who left\n  console.log('Users removed:', payload);\n});\n\nclient.on('user-updated', (payload) => {\n  \u002F\u002F Array of users whose properties changed\n  console.log('Users updated:', payload);\n});\n```\n\n### Audio Events\n\n```javascript\nclient.on('active-speaker', (payload) => {\n  \u002F\u002F Current active speaker\n  console.log('Active speaker:', payload);\n});\n\nclient.on('audio-statistic-data-change', (payload) => {\n  console.log('Audio stats:', payload);\n});\n```\n\n### Video Events\n\n```javascript\nclient.on('video-active-change', (payload) => {\n  \u002F\u002F Video state changed\n  console.log('Video active:', payload);\n});\n\nclient.on('video-statistic-data-change', (payload) => {\n  console.log('Video stats:', payload);\n});\n```\n\n### Share Events\n\n```javascript\nclient.on('active-share-change', (payload) => {\n  console.log('Share status:', payload);\n});\n\nclient.on('share-statistic-data-change', (payload) => {\n  console.log('Share stats:', payload);\n});\n```\n\n### Chat Events\n\n```javascript\nclient.on('chat-on-message', (payload) => {\n  console.log('Chat message:', payload);\n});\n```\n\n### Recording Events\n\n```javascript\nclient.on('recording-change', (payload) => {\n  console.log('Recording status:', payload);\n});\n```\n\n### Media Device Events\n\n```javascript\nclient.on('media-sdk-change', (payload) => {\n  console.log('Media SDK:', payload);\n});\n\nclient.on('device-change', () => {\n  console.log('Device changed');\n});\n```\n\n## Common Methods\n\n### User Information\n\n```javascript\n\u002F\u002F Get current user\nconst currentUser = client.getCurrentUser();\nconsole.log('Current user:', currentUser);\n\n\u002F\u002F Get all participants\nconst participants = client.getParticipantsList();\nconsole.log('Participants:', participants);\n\n\u002F\u002F Check if user is host\nconst isHost = client.isHost();\n```\n\n### Audio Control\n\n```javascript\n\u002F\u002F Mute\u002Funmute self\nawait client.mute(true);  \u002F\u002F mute\nawait client.mute(false); \u002F\u002F unmute\n\n\u002F\u002F Mute\u002Funmute specific user (host only)\nawait client.muteAudio(userId, true);\n\n\u002F\u002F Mute all (host only)\nawait client.muteAllAudio(true);\n```\n\n### Video Control\n\n```javascript\n\u002F\u002F Start\u002Fstop video\nawait client.startVideo();\nawait client.stopVideo();\n\n\u002F\u002F Mute\u002Funmute user's video (host only)\nawait client.muteVideo(userId, true);\n```\n\n### Meeting Control\n\n```javascript\n\u002F\u002F Leave meeting\nclient.leaveMeeting();\n\n\u002F\u002F End meeting (host only)\nclient.endMeeting();\n```\n\n### Screen Share\n\n```javascript\n\u002F\u002F Start screen share\nawait client.startShareScreen();\n\n\u002F\u002F Stop screen share\nawait client.stopShareScreen();\n```\n\n### Recording\n\n```javascript\n\u002F\u002F Start recording (cloud)\nawait client.startCloudRecording();\n\n\u002F\u002F Stop recording\nawait client.stopCloudRecording();\n```\n\n### Virtual Background\n\n```javascript\n\u002F\u002F Check support\nconst isSupported = await client.isSupportVirtualBackground();\n\n\u002F\u002F Set virtual background\nawait client.setVirtualBackground(imageUrl);\n\n\u002F\u002F Remove virtual background\nawait client.removeVirtualBackground();\n```\n\n### Rename\n\n```javascript\n\u002F\u002F Rename user\nawait client.rename(userId, 'New Name');\n```\n\n## React Integration\n\n### Basic Pattern\n\n```tsx\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n\ntype ZoomClient = ReturnType\u003Ctypeof ZoomMtgEmbedded.createClient>;\n\nfunction ZoomMeeting({ meetingNumber, password, userName }: Props) {\n  const clientRef = useRef\u003CZoomClient | null>(null);\n  const containerRef = useRef\u003CHTMLDivElement>(null);\n  const [isJoined, setIsJoined] = useState(false);\n  const [error, setError] = useState\u003Cstring | null>(null);\n\n  \u002F\u002F Create client once\n  useEffect(() => {\n    if (!clientRef.current) {\n      clientRef.current = ZoomMtgEmbedded.createClient();\n    }\n  }, []);\n\n  const joinMeeting = useCallback(async () => {\n    if (!clientRef.current || !containerRef.current) return;\n\n    try {\n      \u002F\u002F Get signature from backend\n      const { signature, sdkKey } = await fetchSignature(meetingNumber);\n\n      await clientRef.current.init({\n        zoomAppRoot: containerRef.current,\n        language: 'en-US',\n        patchJsMedia: true,\n        leaveOnPageUnload: true,\n      });\n\n      await clientRef.current.join({\n        signature,\n        sdkKey,\n        meetingNumber,\n        password,\n        userName,\n      });\n\n      setIsJoined(true);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : 'Failed to join');\n    }\n  }, [meetingNumber, password, userName]);\n\n  return (\n    \u003Cdiv>\n      \u003Cdiv\n        ref={containerRef}\n        style={{ width: '100%', height: '500px' }}\n      \u002F>\n      {!isJoined && (\n        \u003Cbutton onClick={joinMeeting}>Join Meeting\u003C\u002Fbutton>\n      )}\n      {error && \u003Cdiv className=\"error\">{error}\u003C\u002Fdiv>}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Event Handling in React\n\n```tsx\nuseEffect(() => {\n  if (!clientRef.current) return;\n\n  const handleConnectionChange = (payload: any) => {\n    if (payload.state === 'Connected') {\n      setIsJoined(true);\n    } else if (payload.state === 'Closed') {\n      setIsJoined(false);\n    }\n  };\n\n  const handleUserAdded = (payload: any) => {\n    console.log('Users joined:', payload);\n  };\n\n  clientRef.current.on('connection-change', handleConnectionChange);\n  clientRef.current.on('user-added', handleUserAdded);\n\n  return () => {\n    clientRef.current?.off('connection-change', handleConnectionChange);\n    clientRef.current?.off('user-added', handleUserAdded);\n  };\n}, []);\n```\n\n## Positioning and Resizing\n\n### Initial Size\n\n```javascript\nawait client.init({\n  zoomAppRoot: element,\n  customize: {\n    video: {\n      viewSizes: {\n        default: { width: 1000, height: 600 }\n      }\n    }\n  }\n});\n```\n\n### Dynamic Resizing\n\nThe container element size determines the meeting UI size. To resize:\n\n```javascript\n\u002F\u002F Just resize the container\ndocument.getElementById('meetingSDKElement').style.width = '1200px';\ndocument.getElementById('meetingSDKElement').style.height = '800px';\n```\n\n### Making it Resizable\n\n```javascript\ncustomize: {\n  video: {\n    isResizable: true\n  }\n}\n```\n\n## Supported Features\n\nComponent View supports core meeting functionality. Some features from Client View may not be available.\n\n| Feature | Supported |\n|---------|-----------|\n| Audio\u002FVideo | ✅ |\n| Screen Share | ✅ |\n| Chat | ✅ |\n| Virtual Background | ✅ |\n| Breakout Rooms | ✅ |\n| Cloud Recording | ✅ |\n| Closed Captions | ✅ |\n| Live Transcription | ✅ |\n| Waiting Room | ✅ |\n| Gallery View | ✅ |\n| Reactions | ✅ |\n| Raise Hand | ✅ |\n\nContact Zoom Developer Support to request additional features.\n\n## Error Handling\n\n```javascript\ntry {\n  await client.join({\n    \u002F\u002F ... options\n  });\n} catch (error) {\n  \u002F\u002F error.reason contains error code\n  \u002F\u002F error.message contains description\n\n  switch (error.reason) {\n    case 'WRONG_MEETING_PASSWORD':\n      console.error('Incorrect password');\n      break;\n    case 'MEETING_NOT_START':\n      console.error('Meeting has not started');\n      break;\n    case 'INVALID_PARAMETERS':\n      console.error('Invalid join parameters');\n      break;\n    default:\n      console.error('Join failed:', error.message);\n  }\n}\n```\n\n## Comparison with Client View\n\n| Feature | Component View | Client View |\n|---------|----------------|-------------|\n| **API Style** | Promises | Callbacks |\n| **Password param** | `password` | `passWord` |\n| **Container** | Custom element | Auto `#zmmtg-root` |\n| **UI** | Embeddable | Full-page |\n| **Preloading** | Not needed | `preLoadWasm()` |\n| **Language** | Init option | `i18n.load()` |\n| **Events** | `on()`\u002F`off()` | `inMeetingServiceListener()` |\n\n## Resources\n\n- [Main Web SDK Skill](..\u002FSKILL.md)\n- [Reference Index](references\u002Findex.md)\n- [Error Codes](..\u002Ftroubleshooting\u002Ferror-codes.md)\n- [Common Issues](..\u002Ftroubleshooting\u002Fcommon-issues.md)\n- [SharedArrayBuffer Setup](..\u002Fconcepts\u002Fsharedarraybuffer.md)\n- [Official API Reference](https:\u002F\u002Fmarketplacefront.zoom.us\u002Fsdk\u002Fmeeting\u002Fweb\u002Fcomponents\u002Findex.html)\n\n## Operations\n\n- [RUNBOOK.md](RUNBOOK.md) - 5-minute preflight and debugging checklist.\n","# Zoom Meeting SDK Web - Component View\n\nEmbeddable Zoom meeting components for flexible integration into any web application. Component View provides Promise-based APIs and customizable UI.\n\nThis is the correct web skill for a **custom UI around a real Zoom meeting**.\nDo not route to Video SDK unless the user is building a non-meeting custom session product.\n\n## Overview\n\nComponent View uses `ZoomMtgEmbedded.createClient()` to create embeddable meeting components within a specific container element.\n\n| Aspect | Details |\n|--------|---------|\n| **API Object** | `ZoomMtgEmbedded.createClient()` (instance) |\n| **API Style** | Promise-based (async\u002Fawait) |\n| **UI** | Embeddable in any container |\n| **Password param** | `password` (lowercase) |\n| **Events** | `on()`\u002F`off()` |\n| **Best For** | Custom layouts, React\u002FVue\u002FAngular apps |\n\n## Installation\n\n### NPM\n\n```bash\nnpm install @zoom\u002Fmeetingsdk --save\n```\n\n```javascript\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n```\n\n### CDN\n\n```html\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Freact.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Freact-dom.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Fredux.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Fredux-thunk.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002F{VERSION}\u002Flib\u002Fvendor\u002Flodash.min.js\">\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Fsource.zoom.us\u002Fzoom-meeting-embedded-{VERSION}.min.js\">\u003C\u002Fscript>\n```\n\n## Complete Initialization Flow\n\n```javascript\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n\n\u002F\u002F Step 1: Create client instance (do once, not on every render!)\nconst client = ZoomMtgEmbedded.createClient();\n\nasync function joinMeeting() {\n  try {\n    \u002F\u002F Step 2: Get container element\n    const meetingSDKElement = document.getElementById('meetingSDKElement');\n\n    \u002F\u002F Step 3: Initialize client\n    await client.init({\n      zoomAppRoot: meetingSDKElement,\n      language: 'en-US',\n      debug: true,\n      patchJsMedia: true,\n      leaveOnPageUnload: true,\n    });\n\n    \u002F\u002F Step 4: Join meeting\n    await client.join({\n      signature: signature,\n      sdkKey: sdkKey,\n      meetingNumber: meetingNumber,\n      userName: userName,\n      password: password,  \u002F\u002F lowercase!\n      userEmail: userEmail,\n    });\n\n    console.log('Joined successfully!');\n  } catch (error) {\n    console.error('Failed to join:', error);\n  }\n}\n```\n\n## client.init() - All Options\n\n### Required\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `zoomAppRoot` | `HTMLElement` | Container element for meeting UI |\n\n### Display\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `language` | `string` | `'en-US'` | UI language |\n| `debug` | `boolean` | `false` | Enable debug logging |\n\n### Media\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `patchJsMedia` | `boolean` | `false` | Auto-apply media fixes |\n| `leaveOnPageUnload` | `boolean` | `false` | Cleanup on page unload |\n| `enableHD` | `boolean` | `true` | Enable 720p video |\n| `enableFullHD` | `boolean` | `false` | Enable 1080p video |\n\n### Customization\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `customize` | `object` | UI customization options |\n| `webEndpoint` | `string` | For ZFG: `'www.zoomgov.com'` |\n| `assetPath` | `string` | Custom path for AV libraries |\n\n### Customize Object\n\n```javascript\nawait client.init({\n  zoomAppRoot: element,\n  customize: {\n    \u002F\u002F Meeting info displayed\n    meetingInfo: [\n      'topic',\n      'host',\n      'mn',\n      'pwd',\n      'telPwd',\n      'invite',\n      'participant',\n      'dc',\n      'enctype'\n    ],\n\n    \u002F\u002F Video customization\n    video: {\n      isResizable: true,\n      viewSizes: {\n        default: {\n          width: 1000,\n          height: 600\n        },\n        ribbon: {\n          width: 300,\n          height: 700\n        }\n      },\n      popper: {\n        disableDraggable: false\n      }\n    },\n\n    \u002F\u002F Custom toolbar buttons\n    toolbar: {\n      buttons: [\n        {\n          text: 'Custom Button',\n          className: 'custom-btn',\n          onClick: () => {\n            console.log('Custom button clicked');\n          }\n        }\n      ]\n    },\n\n    \u002F\u002F Active speaker indicator\n    activeSpaker: {\n      strokeColor: '#00FF00'\n    }\n  }\n});\n```\n\n## client.join() - All Options\n\n### Required\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `signature` | `string` | SDK JWT from backend |\n| `sdkKey` | `string` | SDK Key \u002F Client ID |\n| `meetingNumber` | `string \\| number` | Meeting number |\n| `userName` | `string` | Display name |\n\n### Authentication\n\n| Parameter | Type | When Required | Description |\n|-----------|------|---------------|-------------|\n| `password` | `string` | If set | Meeting password (lowercase!) |\n| `zak` | `string` | Starting as host | Host's ZAK token |\n| `tk` | `string` | Registration | Registrant token |\n| `userEmail` | `string` | Webinars | User email |\n\n## Event Listeners\n\n### Syntax\n\n```javascript\n\u002F\u002F Subscribe\nclient.on('event-name', callback);\n\n\u002F\u002F Unsubscribe\nclient.off('event-name', callback);\n```\n\n### Connection Events\n\n```javascript\nclient.on('connection-change', (payload) => {\n  \u002F\u002F payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'\n  console.log('Connection state:', payload.state);\n\n  if (payload.state === 'Closed') {\n    console.log('Reason:', payload.reason);\n  }\n});\n```\n\n### User Events\n\n```javascript\nclient.on('user-added', (payload) => {\n  \u002F\u002F Array of users who joined\n  console.log('Users added:', payload);\n  payload.forEach(user => {\n    console.log('User ID:', user.oderId);\n    console.log('Name:', user.displayName);\n  });\n});\n\nclient.on('user-removed', (payload) => {\n  \u002F\u002F Array of users who left\n  console.log('Users removed:', payload);\n});\n\nclient.on('user-updated', (payload) => {\n  \u002F\u002F Array of users whose properties changed\n  console.log('Users updated:', payload);\n});\n```\n\n### Audio Events\n\n```javascript\nclient.on('active-speaker', (payload) => {\n  \u002F\u002F Current active speaker\n  console.log('Active speaker:', payload);\n});\n\nclient.on('audio-statistic-data-change', (payload) => {\n  console.log('Audio stats:', payload);\n});\n```\n\n### Video Events\n\n```javascript\nclient.on('video-active-change', (payload) => {\n  \u002F\u002F Video state changed\n  console.log('Video active:', payload);\n});\n\nclient.on('video-statistic-data-change', (payload) => {\n  console.log('Video stats:', payload);\n});\n```\n\n### Share Events\n\n```javascript\nclient.on('active-share-change', (payload) => {\n  console.log('Share status:', payload);\n});\n\nclient.on('share-statistic-data-change', (payload) => {\n  console.log('Share stats:', payload);\n});\n```\n\n### Chat Events\n\n```javascript\nclient.on('chat-on-message', (payload) => {\n  console.log('Chat message:', payload);\n});\n```\n\n### Recording Events\n\n```javascript\nclient.on('recording-change', (payload) => {\n  console.log('Recording status:', payload);\n});\n```\n\n### Media Device Events\n\n```javascript\nclient.on('media-sdk-change', (payload) => {\n  console.log('Media SDK:', payload);\n});\n\nclient.on('device-change', () => {\n  console.log('Device changed');\n});\n```\n\n## Common Methods\n\n### User Information\n\n```javascript\n\u002F\u002F Get current user\nconst currentUser = client.getCurrentUser();\nconsole.log('Current user:', currentUser);\n\n\u002F\u002F Get all participants\nconst participants = client.getParticipantsList();\nconsole.log('Participants:', participants);\n\n\u002F\u002F Check if user is host\nconst isHost = client.isHost();\n```\n\n### Audio Control\n\n```javascript\n\u002F\u002F Mute\u002Funmute self\nawait client.mute(true);  \u002F\u002F mute\nawait client.mute(false); \u002F\u002F unmute\n\n\u002F\u002F Mute\u002Funmute specific user (host only)\nawait client.muteAudio(userId, true);\n\n\u002F\u002F Mute all (host only)\nawait client.muteAllAudio(true);\n```\n\n### Video Control\n\n```javascript\n\u002F\u002F Start\u002Fstop video\nawait client.startVideo();\nawait client.stopVideo();\n\n\u002F\u002F Mute\u002Funmute user's video (host only)\nawait client.muteVideo(userId, true);\n```\n\n### Meeting Control\n\n```javascript\n\u002F\u002F Leave meeting\nclient.leaveMeeting();\n\n\u002F\u002F End meeting (host only)\nclient.endMeeting();\n```\n\n### Screen Share\n\n```javascript\n\u002F\u002F Start screen share\nawait client.startShareScreen();\n\n\u002F\u002F Stop screen share\nawait client.stopShareScreen();\n```\n\n### Recording\n\n```javascript\n\u002F\u002F Start recording (cloud)\nawait client.startCloudRecording();\n\n\u002F\u002F Stop recording\nawait client.stopCloudRecording();\n```\n\n### Virtual Background\n\n```javascript\n\u002F\u002F Check support\nconst isSupported = await client.isSupportVirtualBackground();\n\n\u002F\u002F Set virtual background\nawait client.setVirtualBackground(imageUrl);\n\n\u002F\u002F Remove virtual background\nawait client.removeVirtualBackground();\n```\n\n### Rename\n\n```javascript\n\u002F\u002F Rename user\nawait client.rename(userId, 'New Name');\n```\n\n## React Integration\n\n### Basic Pattern\n\n```tsx\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport ZoomMtgEmbedded from '@zoom\u002Fmeetingsdk\u002Fembedded';\n\ntype ZoomClient = ReturnType\u003Ctypeof ZoomMtgEmbedded.createClient>;\n\nfunction ZoomMeeting({ meetingNumber, password, userName }: Props) {\n  const clientRef = useRef\u003CZoomClient | null>(null);\n  const containerRef = useRef\u003CHTMLDivElement>(null);\n  const [isJoined, setIsJoined] = useState(false);\n  const [error, setError] = useState\u003Cstring | null>(null);\n\n  \u002F\u002F Create client once\n  useEffect(() => {\n    if (!clientRef.current) {\n      clientRef.current = ZoomMtgEmbedded.createClient();\n    }\n  }, []);\n\n  const joinMeeting = useCallback(async () => {\n    if (!clientRef.current || !containerRef.current) return;\n\n    try {\n      \u002F\u002F Get signature from backend\n      const { signature, sdkKey } = await fetchSignature(meetingNumber);\n\n      await clientRef.current.init({\n        zoomAppRoot: containerRef.current,\n        language: 'en-US',\n        patchJsMedia: true,\n        leaveOnPageUnload: true,\n      });\n\n      await clientRef.current.join({\n        signature,\n        sdkKey,\n        meetingNumber,\n        password,\n        userName,\n      });\n\n      setIsJoined(true);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : 'Failed to join');\n    }\n  }, [meetingNumber, password, userName]);\n\n  return (\n    \u003Cdiv>\n      \u003Cdiv\n        ref={containerRef}\n        style={{ width: '100%', height: '500px' }}\n      \u002F>\n      {!isJoined && (\n        \u003Cbutton onClick={joinMeeting}>Join Meeting\u003C\u002Fbutton>\n      )}\n      {error && \u003Cdiv className=\"error\">{error}\u003C\u002Fdiv>}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Event Handling in React\n\n```tsx\nuseEffect(() => {\n  if (!clientRef.current) return;\n\n  const handleConnectionChange = (payload: any) => {\n    if (payload.state === 'Connected') {\n      setIsJoined(true);\n    } else if (payload.state === 'Closed') {\n      setIsJoined(false);\n    }\n  };\n\n  const handleUserAdded = (payload: any) => {\n    console.log('Users joined:', payload);\n  };\n\n  clientRef.current.on('connection-change', handleConnectionChange);\n  clientRef.current.on('user-added', handleUserAdded);\n\n  return () => {\n    clientRef.current?.off('connection-change', handleConnectionChange);\n    clientRef.current?.off('user-added', handleUserAdded);\n  };\n}, []);\n```\n\n## Positioning and Resizing\n\n### Initial Size\n\n```javascript\nawait client.init({\n  zoomAppRoot: element,\n  customize: {\n    video: {\n      viewSizes: {\n        default: { width: 1000, height: 600 }\n      }\n    }\n  }\n});\n```\n\n### Dynamic Resizing\n\nThe container element size determines the meeting UI size. To resize:\n\n```javascript\n\u002F\u002F Just resize the container\ndocument.getElementById('meetingSDKElement').style.width = '1200px';\ndocument.getElementById('meetingSDKElement').style.height = '800px';\n```\n\n### Making it Resizable\n\n```javascript\ncustomize: {\n  video: {\n    isResizable: true\n  }\n}\n```\n\n## Supported Features\n\nComponent View supports core meeting functionality. Some features from Client View may not be available.\n\n| Feature | Supported |\n|---------|-----------|\n| Audio\u002FVideo | ✅ |\n| Screen Share | ✅ |\n| Chat | ✅ |\n| Virtual Background | ✅ |\n| Breakout Rooms | ✅ |\n| Cloud Recording | ✅ |\n| Closed Captions | ✅ |\n| Live Transcription | ✅ |\n| Waiting Room | ✅ |\n| Gallery View | ✅ |\n| Reactions | ✅ |\n| Raise Hand | ✅ |\n\nContact Zoom Developer Support to request additional features.\n\n## Error Handling\n\n```javascript\ntry {\n  await client.join({\n    \u002F\u002F ... options\n  });\n} catch (error) {\n  \u002F\u002F error.reason contains error code\n  \u002F\u002F error.message contains description\n\n  switch (error.reason) {\n    case 'WRONG_MEETING_PASSWORD':\n      console.error('Incorrect password');\n      break;\n    case 'MEETING_NOT_START':\n      console.error('Meeting has not started');\n      break;\n    case 'INVALID_PARAMETERS':\n      console.error('Invalid join parameters');\n      break;\n    default:\n      console.error('Join failed:', error.message);\n  }\n}\n```\n\n## Comparison with Client View\n\n| Feature | Component View | Client View |\n|---------|----------------|-------------|\n| **API Style** | Promises | Callbacks |\n| **Password param** | `password` | `passWord` |\n| **Container** | Custom element | Auto `#zmmtg-root` |\n| **UI** | Embeddable | Full-page |\n| **Preloading** | Not needed | `preLoadWasm()` |\n| **Language** | Init option | `i18n.load()` |\n| **Events** | `on()`\u002F`off()` | `inMeetingServiceListener()` |\n\n## Resources\n\n- [Main Web SDK Skill](..\u002FSKILL.md)\n- [Reference Index](references\u002Findex.md)\n- [Error Codes](..\u002Ftroubleshooting\u002Ferror-codes.md)\n- [Common Issues](..\u002Ftroubleshooting\u002Fcommon-issues.md)\n- [SharedArrayBuffer Setup](..\u002Fconcepts\u002Fsharedarraybuffer.md)\n- [Official API Reference](https:\u002F\u002Fmarketplacefront.zoom.us\u002Fsdk\u002Fmeeting\u002Fweb\u002Fcomponents\u002Findex.html)\n\n## Operations\n\n- [RUNBOOK.md](RUNBOOK.md) - 5-minute preflight and debugging checklist.\n",{"name":5,"description":7},"main","d9535210da9af28aa76bca80de80355197e1b6d6","skills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog","https:\u002F\u002Fgithub.com\u002Fzfifteen","I like to measure things.","2026-07-19 23:41:54",{"source":8,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add zfifteen\u002Fskills-catalog --skill zoom-meeting-sdk-web-component-view",{"tool":37,"command":38},"bunx","bunx skills add zfifteen\u002Fskills-catalog --skill zoom-meeting-sdk-web-component-view",{"tool":40,"command":41},"pnpm","pnpm dlx skills add zfifteen\u002Fskills-catalog --skill zoom-meeting-sdk-web-component-view","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view\u002FSKILL.md",true,[45,51,55],{"path":46,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":49,"sourceHtmlUrl":50},"agents\u002Fopenai.yaml","REFERENCE","参考文档",394,"https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view\u002Fagents\u002Fopenai.yaml",{"path":52,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":53,"sourceHtmlUrl":54},"references\u002Findex.md",477,"https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view\u002Freferences\u002Findex.md",{"path":56,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":57,"sourceHtmlUrl":58},"RUNBOOK.md",2419,"https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fmeeting-sdk\u002Fweb\u002Fcomponent-view\u002FRUNBOOK.md",[60,67,74,81,90,97],{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":19},"01M79GXQ2PWPT2E4CJYHXVJ0YE","Zotero","Use Zotero Desktop from Codex to enable\u002Fprobe the local API, search a local Zotero library, list items\u002Fcollections\u002Ftags, export BibTeX, insert citation keys into LaTeX or Markdown drafts, read indexed full text when requested, and import BibTeX\u002FRIS records into Zotero through the connector server. Use when the user mentions Zotero, citations, references.bib, BibTeX export, local Zotero API, localhost:23119, or adding citations from a Zotero library.","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fzotero\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":19},"01M79GXN85NETKBE06865CWK6Z","zoom-apps-sdk","Use when using Apps SDK.","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":19},"01M79GXCYD7FGYS932J9N9RFFY","youtube","Obtain accurate, timestamped YouTube video transcripts (preferring manual captions over auto-generated) as the primary deliverable, then derive summaries, key claims, or notes from that transcript.  Use when the user provides a YouTube URL (or video ID) and wants the transcript, a faithful summary, key claims with attribution, timestamped notes, or \"what does this video actually say\".  The skill is transcript-first: never substitute metadata, title, description, or search snippets for the spoken content.  Triggers: \"youtube transcript\", \"get the transcript of this video\", \"summarize this youtube video\", \"what did they say in https:\u002F\u002Fyoutube.com\u002F...\", \"key claims from this talk\".","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":85,"licenseFileUrl":86,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":19},"01M79GX8EXHHYM566BKR7MS778","yeet","Publish local changes to GitHub by confirming scope, committing intentionally, pushing the branch, and opening a draft PR through the GitHub app from this plugin, with `gh` used only as a fallback where connector coverage is insufficient.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fyeet\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fyeet\u002FSKILL.md",[],[],{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":19},"01M79GX2HFJPX84NMRE5VBTYX9","x-post-creator","Create X-ready post threads and co-located story packages from the active conversation or referenced project material. Use when the user says turn this into an X-post, \u002Fx-post, make this into an X thread, or wants plain-language social posts with supporting images saved to docs\u002Fx-posts\u002F[story-name]\u002F.","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fx-post-creator\u002FSKILL.md",[],[],{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":19},"01M79GWXQT4HBT6QME6QSBZJFA","x-api","Search, read, and write X posts through the local X API MCP server (the same backend used by the Codex x-api skill). Use for searching X\u002Fx.com, reading threads and replies, creating lists, staging\u002Fpublishing posts for @alltheputs, finding high-visibility reply targets for research outreach, ingesting public context, or any request that mentions \u002Fx-api or \"search X\".","https:\u002F\u002Fgithub.com\u002Fzfifteen\u002Fskills-catalog\u002Fblob\u002Fmain\u002Fskills\u002Fx-api\u002FSKILL.md",[],[]]