<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jess Mitchell</title>
    <description>The latest articles on DEV Community by Jess Mitchell (@gemontracks).</description>
    <link>https://dev.to/gemontracks</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F15304%2Fe11e12fe-d36d-4333-9ed9-b4d964c889a6.jpeg</url>
      <title>DEV Community: Jess Mitchell</title>
      <link>https://dev.to/gemontracks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gemontracks"/>
    <language>en</language>
    <item>
      <title>Build a video call app with Svelte in an afternoon</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Thu, 06 Jan 2022 13:34:49 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-video-call-app-with-svelte-in-an-afternoon-4h7b</link>
      <guid>https://dev.to/trydaily/build-a-video-call-app-with-svelte-in-an-afternoon-4h7b</guid>
      <description>&lt;p&gt;Daily's JavaScript library, &lt;a href="https://github.com/daily-co/daily-js" rel="noopener noreferrer"&gt;&lt;code&gt;daily-js&lt;/code&gt;&lt;/a&gt;, is compatible with any frontend framework, which means choosing your stack is really up to you. Today we'll be looking at one of our favourite frameworks at Daily...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/MZGH2MEUcfjVvIm2oR/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/MZGH2MEUcfjVvIm2oR/giphy.gif" alt="drumroll"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt;! 🎉&lt;/p&gt;

&lt;p&gt;In today’s tutorial, we’ll rebuild our Daily Prebuilt demo, already built in &lt;a href="https://github.com/daily-demos/prebuilt-ui" rel="noopener noreferrer"&gt;React&lt;/a&gt; and &lt;a href="https://github.com/daily-demos/vue-daily-prebuilt" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, but this time with Svelte! ✨&lt;/p&gt;

&lt;p&gt;Specifically, we’ll cover how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embed &lt;a href="https://daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt; in a Svelte app&lt;/li&gt;
&lt;li&gt;Handle updating your components based on whether you’ve joined a Daily call or not&lt;/li&gt;
&lt;li&gt;Manage your Daily Prebuilt call with a custom control panel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to test the completed version of the demo first, check out the &lt;a href="https://svelte-daily-prebuilt.netlify.app/" rel="noopener noreferrer"&gt;deployed version&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What exactly is Svelte?
&lt;/h2&gt;

&lt;p&gt;Svelte is an open-source frontend component framework that can be used as an alternative to other frontend frameworks, like React or Vue. &lt;/p&gt;

&lt;p&gt;It differs from other frameworks based on how it updates your app’s UI. Instead of using a virtual DOM to handle app changes (like React uses), Svelte is instead a compiler that converts app components to JavaScript and inserts any UI changes directly into the DOM itself. &lt;/p&gt;

&lt;p&gt;Or, as the &lt;a href="https://svelte.dev/blog/svelte-3-rethinking-reactivity" rel="noopener noreferrer"&gt;Svelte docs&lt;/a&gt; put it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you're able to write ambitious applications with excellent performance characteristics.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Who is this tutorial for?
&lt;/h2&gt;

&lt;p&gt;Since this is a Svelte tutorial, the following content will be most helpful for anyone already familiar with Svelte. In case you’re not, we’ll do our best to explain what is unique to Svelte. &lt;/p&gt;

&lt;p&gt;Thankfully, Svelte also has amazing documentation and &lt;a href="https://svelte.dev/tutorial/basics" rel="noopener noreferrer"&gt;interactive tutorials&lt;/a&gt; to learn the basics, and we highly recommend giving those a read!&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;To get started locally, clone the &lt;a href="https://github.com/daily-demos/svelte-daily-prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt Svelte demo app&lt;/a&gt; and run the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also need to &lt;a href="https://dashboard.daily.co/signup" rel="noopener noreferrer"&gt;create a Daily account&lt;/a&gt; and a &lt;a href="https://dashboard.daily.co/rooms/create" rel="noopener noreferrer"&gt;new Daily room&lt;/a&gt; for testing the demo. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The &lt;a href="https://github.com/daily-demos/svelte-daily-prebuilt" rel="noopener noreferrer"&gt;demo README&lt;/a&gt; includes additional instructions for creating new Daily rooms locally via the app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you have the app running locally, navigate to &lt;code&gt;http://localhost:5000&lt;/code&gt; in your browser of choice, and you should see the home page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-home-copy-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-home-copy-1.png" alt="home screen"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;App.svelte&lt;/code&gt;: Determining which view to show
&lt;/h2&gt;

&lt;p&gt;Our app is going to have two possible views:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Our home page, which includes a form to join a call&lt;/li&gt;
&lt;li&gt;The call UI, which includes the Daily Prebuilt embed and our custom call controls&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-16-at-15.32.50%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-16-at-15.32.50%402x.png" alt="2 possible views: call UI and home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We know we'll need some logic to determine which view should show. To determine this, let’s take a look at our parent &lt;a href="https://github.com/daily-demos/svelte-daily-prebuilt/blob/main/src/App.svelte" rel="noopener noreferrer"&gt;&lt;code&gt;App&lt;/code&gt;&lt;/a&gt; component. &lt;code&gt;App&lt;/code&gt; will handle deciding whether the &lt;code&gt;Home&lt;/code&gt; or &lt;code&gt;Call&lt;/code&gt; component is rendered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Call&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./screens/Call.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/Header.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./screens/Home.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  || 'call'&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleJoinCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// set component vars with form submission values&lt;/span&gt;
   &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// save in local storage&lt;/span&gt;
   &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte-prebuilt-url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte-prebuilt-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleLeaveCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;svelte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;crossorigin&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://unpkg.com/@daily-co/daily-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/svelte:head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleJoinCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;{:&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Call&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLeaveCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sr"&gt;/if&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s step through this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the script tag, we start by importing the components we’ll be using (&lt;code&gt;Call&lt;/code&gt;, &lt;code&gt;Home&lt;/code&gt;, and &lt;code&gt;Header&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Then, we declare variables that will be used in this component but are assigned later on.&lt;/li&gt;
&lt;li&gt;Next, we define &lt;code&gt;handleJoinCall&lt;/code&gt;, which we'll describe in more detail below. In short, it sets our &lt;code&gt;currentScreen&lt;/code&gt; variable to &lt;code&gt;call&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We then define &lt;code&gt;handleLeaveCall&lt;/code&gt;, which simply resets &lt;code&gt;currentScreen&lt;/code&gt; to &lt;code&gt;home&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lastly, we import our &lt;code&gt;daily-js&lt;/code&gt; script tag to make the &lt;code&gt;daily-js&lt;/code&gt; library available to the rest of the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s specifically look at the markdown in &lt;code&gt;App&lt;/code&gt; to see how we render our components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleJoinCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;{:&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Call&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLeaveCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sr"&gt;/if&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Svelte, you can conditionally render components based on your JavaScript values using an &lt;a href="https://svelte.dev/tutorial/else-if-blocks" rel="noopener noreferrer"&gt;&lt;code&gt;if&lt;/code&gt; statement&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We know we always want to render our &lt;code&gt;Header&lt;/code&gt;, but we only want to render the &lt;code&gt;Call&lt;/code&gt; component if the user is trying to join a call, i.e. the &lt;code&gt;currentScreen&lt;/code&gt; equals &lt;code&gt;call&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This is where we can use Svelte’s &lt;code&gt;if&lt;/code&gt; syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{#if currentScreen === "home"}&lt;/code&gt; to render the &lt;code&gt;Home&lt;/code&gt; screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{:else}&lt;/code&gt; we can show the &lt;code&gt;Call&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And don’t forget to close your &lt;code&gt;if&lt;/code&gt; block with &lt;code&gt;{/if}&lt;/code&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Listening for custom events
&lt;/h3&gt;

&lt;p&gt;Another handy feature of Svelte is being able to dispatch &lt;a href="https://svelte.dev/tutorial/event-forwarding" rel="noopener noreferrer"&gt;custom events&lt;/a&gt; that can be forwarded to other components. &lt;/p&gt;

&lt;p&gt;Since the &lt;code&gt;Home&lt;/code&gt; component has a form to join calls, we want to call &lt;code&gt;handleJoinCall&lt;/code&gt; (defined in &lt;code&gt;App&lt;/code&gt;) when the form’s &lt;code&gt;submit&lt;/code&gt; event is dispatched. &lt;/p&gt;

&lt;p&gt;Similarly, when you’re in a call and go to leave the call, we want to listen for the custom &lt;code&gt;left&lt;/code&gt; event we'll define in &lt;code&gt;Call&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We handle both situations by adding a custom listener on each component, like so:&lt;br&gt;
&lt;code&gt;&amp;lt;Call on:left={handleLeaveCall} /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Notice how it says &lt;code&gt;on:left&lt;/code&gt;? This will listen for any &lt;code&gt;left&lt;/code&gt; events dispatched. To listen to other custom events you've defined, you can just update the event name, such as &lt;code&gt;on:fancy-event-name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One other thing to note is being able to pass variables to child components. In Svelte, we can pass the &lt;code&gt;userName&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt; values as &lt;a href="https://svelte.dev/tutorial/declaring-props" rel="noopener noreferrer"&gt;props&lt;/a&gt; to the &lt;code&gt;Call&lt;/code&gt; component like so:&lt;br&gt;
 &lt;code&gt;&amp;lt;Call {userName} {url} /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Since the prop name and variable being passed use the same name, we can use the shorthand notation. That is to say, &lt;code&gt;{url}&lt;/code&gt; is shorthand for &lt;code&gt;url={url}&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These properties can then be made available in &lt;code&gt;Call&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Honey, I’m &lt;code&gt;Home.svelte&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-home-copy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-home-copy.png" alt="Home screen again"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;By default, &lt;code&gt;App&lt;/code&gt; will render the &lt;code&gt;Home&lt;/code&gt; component first. &lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;Home&lt;/code&gt; component contains the main content for our app’s home screen. The code for it is a bit longer than &lt;code&gt;App&lt;/code&gt; so we’ll look at the most important sections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Home.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEventDispatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEventDispatcher&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top of our component, we import Svelte’s &lt;a href="https://svelte.dev/tutorial/component-events" rel="noopener noreferrer"&gt;&lt;code&gt;createEventDispatcher&lt;/code&gt; method&lt;/a&gt; and assign it to the variable &lt;code&gt;dispatch&lt;/code&gt;. This method is what we’ll use for dispatching our custom events discussed above. &lt;/p&gt;

&lt;p&gt;Now let’s jump to our HTML and focus on the &lt;code&gt;form&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Home.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home-screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;Prebuilt&lt;/span&gt; &lt;span class="nx"&gt;Svelte&lt;/span&gt; &lt;span class="nx"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Start&lt;/span&gt; &lt;span class="nx"&gt;demo&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;paste&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;own&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
…&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;goToCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
     &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="nx"&gt;required&lt;/span&gt;
     &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://your-domain.daily.co/room-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Join call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have a native HTML &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element with the &lt;code&gt;submit&lt;/code&gt; handler using &lt;code&gt;goToCall&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;form on:submit={goToCall}&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is not a custom event since forms have a native &lt;code&gt;submit&lt;/code&gt; event.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The form has two inputs for a username and Daily room URL. To make each of these input values available in our component’s JavaScript, we can bind each value to a variable declared at the top of the component.&lt;/p&gt;

&lt;p&gt;For example, the username input value will be bound to the variable &lt;code&gt;name&lt;/code&gt;, which is declared at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Home.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;goToCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means when the form’s submit event occurs and the &lt;code&gt;goToCall&lt;/code&gt; method is called, we can use the input values via our bound variables (e.g &lt;code&gt;name&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;This also makes the input values available to forward to the &lt;code&gt;App&lt;/code&gt; component via the &lt;code&gt;dispatch&lt;/code&gt; method we defined before like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Home.svelte&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goToCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;goToCall&lt;/code&gt;, we first prevent the form from refreshing the page with &lt;code&gt;e.preventDefault()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then we use our &lt;code&gt;dispatch&lt;/code&gt; method to &lt;a href="https://svelte.dev/tutorial/event-forwarding" rel="noopener noreferrer"&gt;forward&lt;/a&gt; the &lt;code&gt;submit&lt;/code&gt; event to our &lt;code&gt;App&lt;/code&gt; component. Both &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt; (our variables bound to the inputs) are passed as options to make those values available to &lt;code&gt;App&lt;/code&gt;, as well. &lt;/p&gt;

&lt;p&gt;If you recall from &lt;code&gt;App&lt;/code&gt;, the &lt;code&gt;Home&lt;/code&gt; component has an event listener on it for &lt;code&gt;submit&lt;/code&gt;, which calls the &lt;code&gt;handleJoinCall&lt;/code&gt; method. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Home on:submit={handleJoinCall} /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When our dispatched &lt;code&gt;submit&lt;/code&gt; event registers in &lt;code&gt;App&lt;/code&gt;, it will call &lt;code&gt;handleJoinCall&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleJoinCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;currentScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// set component vars with form submission values&lt;/span&gt;
   &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// save in local storage&lt;/span&gt;
   &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte-prebuilt-url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte-prebuilt-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;handleJoinCall&lt;/code&gt; we update &lt;code&gt;currentScreen&lt;/code&gt; to equal &lt;code&gt;call&lt;/code&gt;. This will cause the &lt;code&gt;Call&lt;/code&gt; component to show instead of &lt;code&gt;Home&lt;/code&gt;. We then set our &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;userName&lt;/code&gt; variables to the values passed from the form and save them in local storage, as well. &lt;/p&gt;

&lt;p&gt;Now that all the &lt;code&gt;Home&lt;/code&gt; form's information is shared with &lt;code&gt;App&lt;/code&gt; — who also shares it with &lt;code&gt;Call&lt;/code&gt; — we can move on to setting up our call UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call on line 1, please
&lt;/h2&gt;

&lt;p&gt;So far we’ve set up our &lt;code&gt;App&lt;/code&gt; component and our &lt;code&gt;Home&lt;/code&gt; screen. Now let’s build our Daily call in &lt;a href="https://github.com/daily-demos/svelte-daily-prebuilt/blob/main/src/screens/Call.svelte" rel="noopener noreferrer"&gt;&lt;code&gt;Call.svelte&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-call-copy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2Fsize%2Fw1600%2F2021%2F12%2Fsvelte-call-copy.png" alt="Diagram of how the Call component is split up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with the &lt;code&gt;Call&lt;/code&gt; component's HTML markdown this time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
 &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;meetingState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call-screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call-screen prejoin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Controls&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;meetingState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleCamera&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;mic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleMic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleScreenShare&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;goFullscreen&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleLocalVideo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleRemoteVideo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a container &lt;code&gt;div&lt;/code&gt; with two children:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Another &lt;code&gt;div&lt;/code&gt;, which is where we’ll embed Daily Prebuilt&lt;/li&gt;
&lt;li&gt;Our &lt;code&gt;Controls&lt;/code&gt; component, which receives the room &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;meetingState&lt;/code&gt;, and call &lt;code&gt;stats&lt;/code&gt; as props. It also has a list of custom event listeners added for each of the control’s buttons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s focus on the Daily call to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedding Daily Prebuilt in your Svelte app
&lt;/h3&gt;

&lt;p&gt;Svelte has a handy &lt;a href="https://svelte.dev/tutorial/onmount" rel="noopener noreferrer"&gt;&lt;code&gt;onMount&lt;/code&gt; lifecycle method&lt;/a&gt; that gets called when the component is first rendered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;onMount&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// assume if the Call component is showing, we should join&lt;/span&gt;
   &lt;span class="nf"&gt;initializeDaily&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We know the &lt;code&gt;Call&lt;/code&gt; component mounts when the form is submitted, so we want to initialize the call as soon as &lt;code&gt;Call&lt;/code&gt; renders. We can do this by calling &lt;code&gt;initializeDaily&lt;/code&gt; on mount.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initializeDaily&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="err"&gt;…&lt;/span&gt;
   &lt;span class="c1"&gt;// select container element to embed Daily iframe in&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// create Daily iframe&lt;/span&gt;
   &lt;span class="nx"&gt;callFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyIframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;iframeStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFRAME_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;showLeaveButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleLeftMeeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// set up interval for retrieving current network stats&lt;/span&gt;
   &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getNetworkStats&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// let the local user join the call, which will cause&lt;/span&gt;
   &lt;span class="c1"&gt;// the call to be displayed in our app UI&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stepping through this &lt;code&gt;initializeDaily&lt;/code&gt; function: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We first select our &lt;code&gt;div&lt;/code&gt; element that will be the Daily Prebuilt iframe’s container: &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;const container = document.getElementById("container");&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next we create our Daily Prebuilt iframe with the &lt;a href="https://docs.daily.co/reference/daily-js/factory-methods/create-frame" rel="noopener noreferrer"&gt;&lt;code&gt;createFrame&lt;/code&gt; method&lt;/a&gt; via &lt;code&gt;daily-js&lt;/code&gt;, and pass the container &lt;code&gt;div&lt;/code&gt; and some call options to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;window.DailyIframe.createFrame(container, options)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Recall: &lt;code&gt;window.DailyIframe&lt;/code&gt; exists because we imported the &lt;code&gt;daily-js&lt;/code&gt; script in &lt;code&gt;App&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next, we add some Daily event listeners so we can update our UI if the local user joins a call, leaves, or there’s a critical error. We’ll explain this a bit more below.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;e.g. &lt;code&gt;callFrame.on("joined-meeting", updateMeetingState);&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Then we set up an interval to get the call’s network stats every 5 seconds so we can display it in our &lt;code&gt;Control&lt;/code&gt; panel. (We won’t go into more detail about this, but &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;ask us if you need help&lt;/a&gt;!)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;interval = setInterval(() =&amp;gt; getNetworkStats(), 5000);&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;And, finally, we use Daily’s &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/join" rel="noopener noreferrer"&gt;&lt;code&gt;join&lt;/code&gt; method&lt;/a&gt; to actually join the call. 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;await callFrame.join();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.14.50.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.14.50.gif" alt="Transitioning from the home screen to video call"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding our custom control panel
&lt;/h2&gt;

&lt;p&gt;As Bruce Springsteen once said, “Honey, I want the heart, I want the soul, I want control right now,” so let’s do just that and add a little more control to our app.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;daily-js&lt;/code&gt; provides instance methods to programmatically do anything you can already do via Daily Prebuilt's UI. This gives a bit more flexibility to how you want to set up your own app’s UI.&lt;/p&gt;

&lt;p&gt;For example, if you want to add a big “Mute” button to your UI, you can! Let’s take a look at how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a Mute button to toggle local audio
&lt;/h3&gt;

&lt;p&gt;As mentioned, our &lt;code&gt;Call&lt;/code&gt; component has a bunch of custom event listeners added to &lt;a href="https://github.com/daily-demos/svelte-daily-prebuilt/blob/main/src/components/Controls.svelte" rel="noopener noreferrer"&gt;&lt;code&gt;Controls&lt;/code&gt;&lt;/a&gt;. This means all the actual Daily logic can stay contained in our &lt;code&gt;Call&lt;/code&gt; component. The &lt;code&gt;Controls&lt;/code&gt; component is basically just UI to dispatch the custom events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Controls&lt;/span&gt;
   &lt;span class="err"&gt;…&lt;/span&gt;
   &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;mic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleMic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;Controls&lt;/code&gt;, we have a button to mute the local user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Controls.svelte&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleToggleMicClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Toggle&lt;/span&gt; &lt;span class="nx"&gt;mic&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/images/mic.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Microphone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On click, this button calls &lt;code&gt;handleToggleMicClick&lt;/code&gt;. That method will then dispatch our &lt;code&gt;toggle-mic&lt;/code&gt; custom event:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleToggleMicClick = () =&amp;gt;  dispatch("toggle-mic");&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Looping back to &lt;code&gt;Call&lt;/code&gt;, the &lt;code&gt;toggle-mic&lt;/code&gt; custom event that is forwarded calls &lt;code&gt;toggleMic&lt;/code&gt; (&lt;code&gt;on:toggle-mic={toggleMic}&lt;/code&gt;), a method defined in &lt;code&gt;Call&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;toggleMic&lt;/code&gt; method is what contains our &lt;code&gt;daily-js&lt;/code&gt; interaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte &lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleMic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noCallFrameError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localVideo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;localVideo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there is no Daily &lt;code&gt;callFrame&lt;/code&gt; – defined in &lt;code&gt;initializeDaily&lt;/code&gt; – we do nothing. This shouldn’t ever happen but, you know, bugs. 🐛&lt;/p&gt;

&lt;p&gt;Next, we get our current local audio state (muted or unmuted) via the &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/local-audio" rel="noopener noreferrer"&gt;&lt;code&gt;localAudio&lt;/code&gt; Daily method&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const localVideo = callFrame.localAudio();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Whatever the current value is, we want to make it the opposite. To do this, we can use the &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/set-local-audio" rel="noopener noreferrer"&gt;&lt;code&gt;setLocalAudio&lt;/code&gt; instance method&lt;/a&gt; and set our local audio to the inverse boolean value. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;callFrame.setLocalAudio(!localVideo);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once that’s called, your unmuted audio will mute, or vice versa! 💪&lt;/p&gt;

&lt;p&gt;We won’t cover all the buttons in the control panel since they all follow a similar pattern, but if you need help, &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;please let us know&lt;/a&gt;! 🤗&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.20.49.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.20.49.gif" alt="Muting yourself with a custom Mute button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Appetite for (call) destruction
&lt;/h2&gt;

&lt;p&gt;To understand how the Daily event listeners work a bit more, let’s use the &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#left-meeting" rel="noopener noreferrer"&gt;&lt;code&gt;left-meeting&lt;/code&gt; event&lt;/a&gt; as an example. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;Call&lt;/code&gt;, we added an event listener for &lt;code&gt;left-meeting&lt;/code&gt;, which calls a callback method (&lt;code&gt;handleLeftMeeting&lt;/code&gt;) when triggered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;

&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleLeftMeeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// in initializeDaily()&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleLeftMeeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback, &lt;code&gt;handleLeftMeeting&lt;/code&gt;, gets called when the local user clicks the &lt;code&gt;Leave&lt;/code&gt; button via Daily Prebuilt’s UI. It then dispatches a custom event (&lt;code&gt;left&lt;/code&gt;) that &lt;code&gt;App&lt;/code&gt; is listening for. &lt;/p&gt;

&lt;p&gt;It does a couple other clean up tasks as well, but we won't worry about that for now. Essentially, it resets our app’s state.&lt;/p&gt;

&lt;p&gt;If you recall, &lt;code&gt;App&lt;/code&gt; has a listener on the &lt;code&gt;Call&lt;/code&gt; component for a custom &lt;code&gt;left&lt;/code&gt; event:&lt;br&gt;
&lt;code&gt;&amp;lt;Call {userName} {url} on:left={handleLeaveCall} /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;handleLeaveCall&lt;/code&gt; gets called, which resets our &lt;code&gt;currentScreen&lt;/code&gt; value to &lt;code&gt;home&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleLeaveCall = () =&amp;gt; currentScreen = "home";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;currentScreen&lt;/code&gt; gets reset to &lt;code&gt;home&lt;/code&gt;, &lt;code&gt;App&lt;/code&gt; will render the &lt;code&gt;Home&lt;/code&gt; component instead of &lt;code&gt;Call&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.24.41.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F12%2FCleanShot-2021-12-30-at-11.24.41.gif" alt="Leaving the call and going back to the home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve come full circle back home! 🍩&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/tDJYUdv3osmDs5HlyU/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/tDJYUdv3osmDs5HlyU/giphy.gif" alt="full circle"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  Cleaning up after the party
&lt;/h3&gt;

&lt;p&gt;Now that we have reset our state to get back to the home screen, we still have a little leftover clean up to do.&lt;/p&gt;

&lt;p&gt;If you recall, we added some Daily event listeners to our &lt;code&gt;callFrame&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;As a final step, we can turn off those event listeners and destroy our Daily &lt;code&gt;callFrame&lt;/code&gt;. It will be recreated when the next call is joined so we don't need it hanging around after leaving this call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Call.svelte&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onDestroy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// remove event listeners&lt;/span&gt;
      &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateMeetingState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleLeftMeeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// destroy Daily callframe after call ends&lt;/span&gt;
      &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Svelte provides an &lt;code&gt;onDestroy&lt;/code&gt; &lt;a href="https://svelte.dev/tutorial/ondestroy" rel="noopener noreferrer"&gt;lifecycle method&lt;/a&gt; that will be triggered when the &lt;code&gt;Call&lt;/code&gt; component is destroyed.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;onDestroy&lt;/code&gt;, we can turn off our Daily event listeners and destroy the &lt;code&gt;callFrame&lt;/code&gt; with Daily's &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/destroy" rel="noopener noreferrer"&gt;&lt;code&gt;destroy&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We hope this tutorial helps you get started with building your own Daily video apps in Svelte. To learn more about Daily Prebuilt, check out our &lt;a href="https://www.daily.co/blog/tag/daily-prebuilt/" rel="noopener noreferrer"&gt;other Daily Prebuilt blog posts&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you’d like to build something more custom, keep an eye out on &lt;a href="https://twitter.com/trydaily" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; for our next Svelte tutorial! 👀&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a real-time video chat app with React Native</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Mon, 29 Nov 2021 19:21:35 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-real-time-video-chat-app-with-react-native-2hm</link>
      <guid>https://dev.to/trydaily/build-a-real-time-video-chat-app-with-react-native-2hm</guid>
      <description>&lt;p&gt;Daily’s &lt;a href="https://github.com/daily-co/react-native-daily-js" rel="noopener noreferrer"&gt;React Native library&lt;/a&gt; allows developers to build mobile apps compatible with both Android and iOS with one codebase. It also means your web developers, who have &lt;em&gt;likely&lt;/em&gt; crossed paths with &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; at some point, can write code that will get compiled into native mobile code with a smaller learning curve, since React and React Native are fairly similar.&lt;/p&gt;

&lt;p&gt;Recently on the Daily blog, we discussed how to &lt;a href="https://www.daily.co/blog/build-your-own-audio-only-clubhouse-clone-app-with-dailys-react-native-library/" rel="noopener noreferrer"&gt;build your own audio call app&lt;/a&gt; in React Native. That tutorial specifically looked at Daily’s &lt;a href="https://github.com/daily-demos/party-line/tree/main/react-native" rel="noopener noreferrer"&gt;Party Line demo app&lt;/a&gt;, which was built to handle the use case where every call is always audio-only.&lt;/p&gt;

&lt;h3&gt;
  
  
  Today's agenda
&lt;/h3&gt;

&lt;p&gt;In today’s tutorial, we’ll take a look at Daily’s React Native &lt;a href="https://github.com/daily-co/react-native-daily-js-playground" rel="noopener noreferrer"&gt;Playground demo app&lt;/a&gt;, which uses more of a traditional video call format; call participants have the option to turn on and off both audio and video. &lt;/p&gt;

&lt;p&gt;More specifically, we’ll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to build a multi-participant video call in React Native with &lt;a href="https://github.com/daily-co/react-native-daily-js" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-daily-js&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;How to give call participants control of their devices in the video call to toggle their local microphone and camera&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Who is this tutorial for?
&lt;/h2&gt;

&lt;p&gt;If you are interested in building a mobile app with video calls and have some React Native (or even React) knowledge, this tutorial is for you. React Native projects can be a little more finicky to run locally than web apps because of the platform-specific setup requirements, so having some comfort with React Native is a big plus.&lt;/p&gt;

&lt;p&gt;We won’t cover every section of the &lt;a href="https://github.com/daily-co/react-native-daily-js-playground" rel="noopener noreferrer"&gt;Playground demo app&lt;/a&gt; code base in this tutorial since a lot of the functionality is similar to &lt;code&gt;daily-js&lt;/code&gt; (web) apps, which we promise already have a bunch of &lt;a href="https://www.daily.co/blog/tag/custom-daily/" rel="noopener noreferrer"&gt;existing tutorials&lt;/a&gt;.📚 &lt;/p&gt;

&lt;h3&gt;
  
  
  A note on today’s stack and React Hooks
&lt;/h3&gt;

&lt;p&gt;Since this app is written in React Native, we’ll be looking at React Native code examples and React hooks from the demo codebase. We recommend familiarizing yourself with &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;React Hooks&lt;/a&gt; before reading on to get the most out of this tutorial.&lt;/p&gt;

&lt;p&gt;We’ve also used &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; in this demo app. TypeScript isn’t specifically discussed below, but having some familiarity with it will help you review the code examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;For anyone new to React Native app development, we’ll quickly cover some basics.&lt;/p&gt;

&lt;p&gt;Typically, you’ll want to test on both Android and iOS mobile or tablet devices to ensure your app is working in both operating systems. To test on iOS devices, you’ll need to download &lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;XCode&lt;/a&gt;, which is only available to download on Mac computers. (You’ll also want to pour yourself a coffee or two while it downloads and hope you’re not on deadline. ☕)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This means you will need a Mac to access XCode for iOS development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Android, however, can be tested with &lt;a href="https://developer.android.com/studio?gclid=CjwKCAiA7dKMBhBCEiwAO_crFAXL7AiOJQ7v-vpnt6HBCtd4Xy1h114KWPvJOES-XFGyqpkxIqaVABoCwesQAvD_BwE&amp;amp;gclsrc=aw.ds#downloads" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt;, which is available on a range of operating systems.&lt;/p&gt;

&lt;p&gt;In terms of running the &lt;a href="https://github.com/daily-co/react-native-daily-js-playground" rel="noopener noreferrer"&gt;Daily Playground demo app&lt;/a&gt; locally, thorough instructions for both Android and iOS development are included in the &lt;a href="https://github.com/daily-co/react-native-daily-js-playground/blob/main/README.md" rel="noopener noreferrer"&gt;repo’s README&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You’ll need to use real devices instead of a device emulator when you’re testing the video/audio features. In terms of which OS to start with, if you don’t have a personal preference, it’s typically faster to get this app running on an Android device.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  App features and functionality
&lt;/h2&gt;

&lt;p&gt;As mentioned, we won’t cover every part of this codebase. To start, let’s discuss the overall structure and functionality of the app so you know how to navigate it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;App&lt;/code&gt; component is the top-level parent component. It renders either the home screen or the in-call view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-screens.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-screens.png" alt="Two app views: home screen and in-call"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Let’s quickly review how the home screen works.&lt;/p&gt;

&lt;p&gt;When you first land on the home screen, there’s an empty room URL text input, a “Create demo room” button, and a disabled “Join call” button. &lt;/p&gt;

&lt;p&gt;If you know which Daily room you want to join, you can enter the room URL in the text input and press “Join call”, which will be enabled once the input has a value.&lt;/p&gt;

&lt;p&gt;If you do &lt;em&gt;not&lt;/em&gt; have a room URL, we’ve set up an endpoint that will create a new room for you using &lt;a href="https://docs.daily.co/reference/rest-api/rooms/create-room" rel="noopener noreferrer"&gt;Daily’s REST API&lt;/a&gt;. This endpoint is called when the “Create room” button is pressed, which calls the method &lt;code&gt;createRoom&lt;/code&gt;, defined in &lt;code&gt;App&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createRoom&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Creating&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Creating room...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create demo room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;setRoomCreateError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Creating&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;api&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setRoomUrlFieldValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Idle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setRoomCreateError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setRoomUrlFieldValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Idle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we update our &lt;code&gt;appState&lt;/code&gt; state value to be in a temporary “creating” state, call &lt;code&gt;api.createRoom()&lt;/code&gt;, and, if it’s successful, set our &lt;code&gt;roomUrlFieldValue&lt;/code&gt; value and &lt;code&gt;appState&lt;/code&gt;. (Both &lt;code&gt;appState&lt;/code&gt; and &lt;code&gt;roomUrlFieldValue&lt;/code&gt; are component state values initialized in &lt;code&gt;App&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Take a look at &lt;a href="https://github.com/daily-co/react-native-daily-js-playground/blob/main/DailyPlayground/src/api.ts" rel="noopener noreferrer"&gt;api.ts&lt;/a&gt; to see the &lt;code&gt;api.createRoom()&lt;/code&gt; method.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Whether you use your own Daily room URL or one created in the app, when you press the “Join call” button, it will take the &lt;code&gt;roomUrlFieldValue&lt;/code&gt;, set the &lt;code&gt;roomUrl&lt;/code&gt; state value with it, and kick off creating the Daily &lt;a href="https://docs.daily.co/call-object" rel="noopener noreferrer"&gt;call object&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here we have the “Join call” button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="c1"&gt;// “Join call” button will call startCall on press&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StartButton&lt;/span&gt;
   &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;startCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;startButtonDisabled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;starting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Joining&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we call &lt;code&gt;startCall&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="cm"&gt;/**
  * Join the room provided by the user or the
  * temporary room created by createRoom
 */&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;setRoomUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomUrlFieldValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And lastly, a &lt;code&gt;useEffect&lt;/code&gt; hook is triggered by the &lt;code&gt;roomURL&lt;/code&gt; value getting updated, which creates our Daily call object (the brain of this operation!)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="cm"&gt;/**
  * Create the callObject as soon as we have a roomUrl.
  * This will trigger the call starting.
  */&lt;/span&gt;
 &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newCallObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCallObject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nf"&gt;setCallObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newCallObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following line is where the call object is actually created:&lt;br&gt;
&lt;code&gt;const newCallObject = Daily.createCallObject();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, by setting that value in our component’s state, the call object instance can be referred to later:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setCallObject(newCallObject);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After the call object has been created, we can then actually join our room (finally! Considering we pressed the “Join call” button 😉)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
 &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// Doing nothing here since we handle fatal join errors in another way,&lt;/span&gt;
     &lt;span class="c1"&gt;// via our listener attached to the 'error' event&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Joining&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, in another &lt;code&gt;useEffect&lt;/code&gt; hook in &lt;code&gt;App&lt;/code&gt;, when the &lt;code&gt;callObject&lt;/code&gt; and &lt;code&gt;roomUrl&lt;/code&gt; state values are truthy, which they now are, we can actually &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/join" rel="noopener noreferrer"&gt;&lt;code&gt;join&lt;/code&gt;&lt;/a&gt; our call by passing the &lt;code&gt;roomUrl&lt;/code&gt; to our call object instance. &lt;/p&gt;

&lt;p&gt;This step is also where our app view will change from the home screen to the in-call view. This happens because of this line in the effect above: &lt;code&gt;setAppState(AppState.Joining);&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showCallPanel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Joining&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Joined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;showCallPanel&lt;/code&gt; — shown above — is truthy, our in-call view will render instead of the home screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showCallPanel&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
             &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callContainerBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Orientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Landscape&lt;/span&gt;
                    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callContainerLandscape&lt;/span&gt;
                    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CallPanel&lt;/span&gt; &lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tray&lt;/span&gt;
                &lt;span class="nx"&gt;onClickLeaveCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;enableCallButtons&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
             &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="c1"&gt;//home screen&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll leave it at that for the home screen and focus on the &lt;code&gt;CallPanel&lt;/code&gt; component — our in-call view — for the rest of this tutorial. If you have any questions about this section, please &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;reach out&lt;/a&gt;! We’re happy to help. 🙌&lt;/p&gt;




&lt;h2&gt;
  
  
  Displaying video tiles in your Daily React Native app
&lt;/h2&gt;

&lt;p&gt;Let’s start by familiarizing ourselves with what our in-call app UI is supposed to look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-25-at-15.44.03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-25-at-15.44.03.png" alt="In-call UI featuring a developer talking to herself"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We have the local participant’s camera feed at the top left corner, the room URL and a button to copy it to your clipboard in the middle of the screen, and our tray at the bottom. If anyone is screen sharing, they’ll also be included as a small thumbnail at the top.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Screen sharing can’t be initiated in this app but call participants can join the room from any platform, including a web app using &lt;code&gt;daily-js&lt;/code&gt;, where &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/start-screen-share" rel="noopener noreferrer"&gt;screen sharing&lt;/a&gt; is permitted.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The tray (i.e. the &lt;code&gt;Tray&lt;/code&gt; component) has buttons to toggle the local participant’s audio, video, and to leave the call.&lt;/p&gt;

&lt;p&gt;When more participants join, their videos are shown in the middle of the screen, replacing the room URL information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterating over our participant list
&lt;/h3&gt;

&lt;p&gt;Now that we know what we’re talking about, let’s jump right to where we’re actually creating our participant videos with &lt;code&gt;react-native-daily-js&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;CallPanel.tsx&lt;/code&gt;, we render an array called &lt;code&gt;largeTiles&lt;/code&gt;, which represents the remote participants.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CallPanel.tsx&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScrollView&lt;/span&gt;
     &lt;span class="nx"&gt;alwaysBounceVertical&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;alwaysBounceHorizontal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;horizontal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Orientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Landscape&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
            &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;largeTilesContainerInnerBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Orientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Portrait&lt;/span&gt;
                 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;largeTilesContainerInnerPortrait&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;largeTilesContainerInnerLandscape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;]}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;largeTiles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- our remote participants&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ScrollView&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: We’ve put this in a &lt;a href="https://reactnative.dev/docs/scrollview" rel="noopener noreferrer"&gt;&lt;code&gt;ScrollView&lt;/code&gt;&lt;/a&gt; but you may prefer a &lt;a href="https://reactnative.dev/docs/flatlist" rel="noopener noreferrer"&gt;&lt;code&gt;FlatList&lt;/code&gt;&lt;/a&gt; component if you know you will be having larger calls. (A &lt;code&gt;FlatList&lt;/code&gt; will only render the visible tiles, which should help with performance. It’s less of a concern in 1-on-1 video calls.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;largeTiles&lt;/code&gt; (remote participants) and &lt;code&gt;thumbnailTiles&lt;/code&gt; (the local participant or screen sharer) are determined by the same &lt;a href="https://reactjs.org/docs/hooks-reference.html#usememo" rel="noopener noreferrer"&gt;memoized&lt;/a&gt; function. The tiles in &lt;code&gt;largeTiles&lt;/code&gt; can be either full size or half size depending on the number of participants.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-multi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-multi.png" alt="Full and half size remote participant tiles"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CallPanel.tsx&lt;/span&gt;
 &lt;span class="cm"&gt;/**
  * Get lists of large tiles and thumbnail tiles to render.
  */&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;largeTiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thumbnailTiles&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;larges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;thumbnails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
   &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callItem&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;tileType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isScreenShare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;tileType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Full&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLocal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;containsScreenShare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;tileType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thumbnail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;participantCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;tileType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Full&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;tileType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Half&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tile&lt;/span&gt;
         &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="nx"&gt;videoTrackState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;callItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="nx"&gt;audioTrackState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;callItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="nx"&gt;mirror&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usingFrontCamera&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isLocal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
         &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tileType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="nx"&gt;disableAudioIndicators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;isScreenShare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
         &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;isLocal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;flipCamera&lt;/span&gt;
             &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                 &lt;span class="nf"&gt;sendHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tileType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thumbnail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;thumbnails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;larges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;larges&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thumbnails&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flipCamera&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendHello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usingFrontCamera&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s step through this function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We declare two arrays that we’ll be updating in this function: &lt;code&gt;larges&lt;/code&gt; and &lt;code&gt;thumbnails&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We get an array of our call participants (&lt;code&gt;Object.entries(callState.callItems)&lt;/code&gt;) and do the following for each (or &lt;code&gt;forEach&lt;/code&gt;, if you will):

&lt;ul&gt;
&lt;li&gt;_Note: The &lt;code&gt;tileType&lt;/code&gt; can be &lt;code&gt;TileType.Full&lt;/code&gt;, &lt;code&gt;TileType.Half&lt;/code&gt;, or  &lt;code&gt;TileType.Thumbnail&lt;/code&gt;.  The latter is the local participant, and the first two options are for remote participants (our &lt;code&gt;largeTiles&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;If the “participant” is actually a screen share, we make it a full size tile&lt;/li&gt;
&lt;li&gt;If the participant is local or currently sharing their screen, we make them a thumbnail&lt;/li&gt;
&lt;li&gt;If the call has 3 or less participants total, remote participants will have full size tiles; otherwise, they’ll have half size tiles.&lt;/li&gt;
&lt;li&gt;We then render a &lt;code&gt;Tile&lt;/code&gt; component for each participant and update our &lt;code&gt;larges&lt;/code&gt; and &lt;code&gt;thumbnails&lt;/code&gt; arrays&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Okay, we’ve come pretty far but we still need to render our actual video and audio for the participants, so bear with us!&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering participant media
&lt;/h3&gt;

&lt;p&gt;The most important part of the &lt;code&gt;Tile&lt;/code&gt; component is the &lt;code&gt;mediaComponent&lt;/code&gt;, a memoized instance of the &lt;code&gt;DailyMediaView&lt;/code&gt; component imported from &lt;code&gt;react-native-daily-js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tile.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;DailyMediaView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@daily-co/react-native-daily-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mediaComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DailyMediaView&lt;/span&gt;
       &lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;mirror&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mirror&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;zOrder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thumbnail&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;media&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;objectFit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cover&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mirror&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;videoTrack&lt;/code&gt; and &lt;code&gt;audioTrack&lt;/code&gt; are props passed to &lt;code&gt;Tile&lt;/code&gt; from &lt;code&gt;CallPanel&lt;/code&gt; but are actually set in &lt;code&gt;callState.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// callState.ts&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCallItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;DailyParticipant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// Ensure we *always* have a local participant&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;callItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;initialCallState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callItems&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 
 &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shouldIncludeScreenCallItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-screen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenVideo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenAudio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;callItems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re jumping around here a bit but the important thing to understand is that our Daily &lt;code&gt;callObject&lt;/code&gt; provides our participant information (see: &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/participants" rel="noopener noreferrer"&gt;&lt;code&gt;callObject.participants()&lt;/code&gt;&lt;/a&gt;) and our participant information contains their media (video/audio) tracks. We can then pass those tracks to the &lt;code&gt;DailyMediaView&lt;/code&gt; component to actually play those tracks in the app. &lt;/p&gt;

&lt;p&gt;Jumping back to the &lt;code&gt;Tile&lt;/code&gt; component, we get the &lt;code&gt;videoTrack&lt;/code&gt; and &lt;code&gt;audioTrack&lt;/code&gt; values from the &lt;code&gt;videoTrackState&lt;/code&gt; and &lt;code&gt;audioTrackState&lt;/code&gt; props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tile.tsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrackState&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
     &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrackState&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioTrackState&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
     &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioTrackState&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means we use the tracks from the individual participant information if they’re available, and otherwise set that corresponding props to &lt;code&gt;null&lt;/code&gt;. Both are valid types for the &lt;code&gt;DailyMediaView&lt;/code&gt; &lt;code&gt;videoTrack&lt;/code&gt; and &lt;code&gt;audioTrack&lt;/code&gt; props.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Tile&lt;/code&gt; also has an overlay with the audio and camera muted icons when they apply (i.e. when there’s no track to play), but we won’t review that code here. Again, &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;let us know&lt;/a&gt; if you have any questions. 🙏&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdailyco.ghost.io%2F4a66d8b2-c8c1-4296-9824-7cf2eac74085" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdailyco.ghost.io%2F4a66d8b2-c8c1-4296-9824-7cf2eac74085" alt="Tile icon overlay"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  Controlling your local devices in-call
&lt;/h2&gt;

&lt;p&gt;As a final note, let’s see how our &lt;code&gt;Tray&lt;/code&gt; component interacts with the Daily call object. As a reminder, it’s rendered in &lt;code&gt;App.tsx&lt;/code&gt; at the same time the &lt;code&gt;CallPanel&lt;/code&gt; component is rendered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-tray.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fandroid-tray.png" alt="Tray on Android"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, the tray lets up control our local camera and microphone, as well as leave the current call to return to the home screen. &lt;/p&gt;

&lt;p&gt;To toggle our local camera, we can call &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/set-local-video" rel="noopener noreferrer"&gt;&lt;code&gt;setLocalAudio&lt;/code&gt;&lt;/a&gt; on the call object instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tray.tsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleCamera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;setLocalVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isCameraMuted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isCameraMuted&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, we can toggle our microphone on or off with &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/set-local-audio" rel="noopener noreferrer"&gt;&lt;code&gt;setLocalAudio&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tray.tsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleMic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;setLocalAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isMicMuted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isMicMuted&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, pressing the “Leave” button will call the &lt;code&gt;leaveCall&lt;/code&gt; function call, a prop passed from &lt;code&gt;App&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="cm"&gt;/**
  * Leave the current call.
  * If we're in the error state (AppState.Error),
  * we've already "left", so just
  * clean up our state.
  */&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaveCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setRoomUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setRoomUrlFieldValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setCallObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Idle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;setAppState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Leaving&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;appState&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/destroy" rel="noopener noreferrer"&gt;&lt;code&gt;destroy&lt;/code&gt;&lt;/a&gt;ing our call object instance and resetting the state in &lt;code&gt;App&lt;/code&gt; to get back to our initial values.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;We hope this helps you navigate building your own video call apps with Daily’s React Native library. We covered the most important aspects of our &lt;a href="https://github.com/daily-co/react-native-daily-js-playground/blob/main/DailyPlayground/src/api.ts" rel="noopener noreferrer"&gt;Playground app&lt;/a&gt; but we’re always happy to answer any questions you may have! 😁&lt;/p&gt;

&lt;p&gt;If you’re looking to learn more about building with Daily’s React Native library, check out our beloved &lt;a href="https://docs.daily.co/reference/rn-daily-js" rel="noopener noreferrer"&gt;docs&lt;/a&gt; or read our previous tutorial on building a Clubhouse clone app. 📱&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a mobile audio chat app in an afternoon with React Native</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Wed, 24 Nov 2021 15:35:01 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-mobile-audio-call-app-in-an-afternoon-with-react-native-3j3g</link>
      <guid>https://dev.to/trydaily/build-a-mobile-audio-call-app-in-an-afternoon-with-react-native-3j3g</guid>
      <description>&lt;p&gt;At Daily, one of our primary focuses has been &lt;a href="https://www.daily.co/audio-only" rel="noopener noreferrer"&gt;supporting audio-only apps&lt;/a&gt; with our APIs. Lately, we’ve been hearing more and more discussions about how to help app users avoid &lt;a href="https://news.stanford.edu/2021/02/23/four-causes-zoom-fatigue-solutions/" rel="noopener noreferrer"&gt;Zoom fatigue&lt;/a&gt; — the feeling of being burnt out from sitting in video calls all day long.&lt;/p&gt;

&lt;p&gt;Audio-only apps are a great solution to this issue as they typically require less cognitive resources to participate in. They are also a great option for larger calls or calls on mobile devices as they tend to have lower CPU requirements. (So you &lt;em&gt;and&lt;/em&gt; your devices need to think less. 😉) &lt;/p&gt;

&lt;p&gt;To help our customers support their &lt;a href="https://www.daily.co/blog/audio-only-social-networks-what-are-they-and-how-are-they-being-used/" rel="noopener noreferrer"&gt;audio-only use cases&lt;/a&gt;, we launched an audio &lt;a href="https://www.producthunt.com/posts/audio-apps-starter-kit" rel="noopener noreferrer"&gt;starter kit&lt;/a&gt; (a.k.a. Party Line) earlier this year, which includes demo apps in &lt;a href="https://github.com/daily-demos/party-line/tree/main/react" rel="noopener noreferrer"&gt;React (web)&lt;/a&gt;, &lt;a href="https://github.com/daily-demos/party-line/tree/main/ios" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;, &lt;a href="https://github.com/daily-demos/party-line/tree/main/android" rel="noopener noreferrer"&gt;Android&lt;/a&gt;, and &lt;a href="https://github.com/daily-demos/party-line/tree/main/react-native" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In today's tutorial, we’ll be doing a deeper dive into how the &lt;a href="https://github.com/daily-demos/party-line/tree/main/react" rel="noopener noreferrer"&gt;React Native version of Party Line&lt;/a&gt; works. &lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you’ll know how to build a &lt;a href="https://www.joinclubhouse.com/" rel="noopener noreferrer"&gt;Clubhouse&lt;/a&gt;-esque Daily audio app using our &lt;a href="https://github.com/daily-co/react-native-daily-js" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-daily-js&lt;/code&gt;&lt;/a&gt; library and Daily’s customizable &lt;a href="https://docs.daily.co/call-object" rel="noopener noreferrer"&gt;call object&lt;/a&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  Who is this tutorial for?
&lt;/h2&gt;

&lt;p&gt;To get the most out of this tutorial, some basic React Native knowledge is useful. If you’ve never used React Native before but are familiar with React and React hooks, you should be able to follow along. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: React and React Native code is fairly similar but does have some differences, so we’ll do our best to explain those differences as they come up!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting set up locally
&lt;/h2&gt;

&lt;p&gt;To run the Party Line app locally, follow the instructions located in the &lt;a href="https://github.com/daily-demos/party-line/tree/main/react-native" rel="noopener noreferrer"&gt;Github repo’s README&lt;/a&gt;. Instructions for both iOS and Android are included, depending which OS you prefer to primarily test React Native apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature set and backlog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-18-at-14.47.58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-18-at-14.47.58.png" alt="Party Line app views"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s start by describing which audio call features will (and won’t) be included.&lt;/p&gt;

&lt;p&gt;Party Line will include two views:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A home screen with a form to join or create an audio call&lt;/li&gt;
&lt;li&gt;An in-call view once a call has been joined&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's review some of the basic functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the home screen, the local user can fill out their name in the form and either specify a room code or leave the code blank. If they leave the code blank, Party Line will automatically create a new room and join it when the form is submitted. &lt;/li&gt;
&lt;li&gt;Each room created in Party Line will expire after 10 minutes. The expiry is set when the room is created via the &lt;a href="https://docs.daily.co/reference/rest-api/rooms/create-room" rel="noopener noreferrer"&gt;Daily REST API&lt;/a&gt; and something we’ve included to avoid long-living demo rooms. This can be adjusted in the room settings to match your use case, however.&lt;/li&gt;
&lt;li&gt;Once the room is joined, the room code can be shared with anyone. Rooms created from one app are compatible with any of our other Party Line apps (iOS, Android, React/web, or React Native). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll allow for three different types of participants: moderator, speaker, listener. &lt;/p&gt;

&lt;p&gt;Participant types are handled as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The room creator is the moderator&lt;/li&gt;
&lt;li&gt;Moderators are indicated in the UI by a star next to their initials&lt;/li&gt;
&lt;li&gt;Moderators can promote listeners to speakers, speakers to listeners, and anyone to a moderator&lt;/li&gt;
&lt;li&gt;Listeners can raise (or lower) their hands to indicate they would like to speak&lt;/li&gt;
&lt;li&gt;Speakers and moderators can mute/unmute themselves, but only mute others&lt;/li&gt;
&lt;li&gt;When a moderator leaves the call and there are no other moderators present, the call ends for everyone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.04.00.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.04.00.gif" alt="Moderator updating their local audio settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In terms of constraints, we will not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use any external account management or authentication&lt;/li&gt;
&lt;li&gt;Have a database, though we recommend handling the participant types with a database for production-level apps (❗)&lt;/li&gt;
&lt;li&gt;Have a backend aside from serverless functions, which call the Daily REST API&lt;/li&gt;
&lt;li&gt;Offer a list of rooms to join; the participant will need to know the code for the room they want to join. This would be a great feature to add, though 😉&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll cover how most of this works below or share links to existing resources for anything we don’t have time to go over.&lt;/p&gt;




&lt;h2&gt;
  
  
  Component structure
&lt;/h2&gt;

&lt;p&gt;Before we dive into the code, let’s plan the structure we’re going to use for our components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FPartyLineFinal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FPartyLineFinal.png" alt="Component structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we have our &lt;code&gt;App&lt;/code&gt; component as the top-level parent component. It will render the &lt;code&gt;Header&lt;/code&gt; component with the app title and information. It will also conditionally render &lt;em&gt;either&lt;/em&gt; the &lt;code&gt;InCall&lt;/code&gt; component, which handles the Daily audio call, &lt;em&gt;or&lt;/em&gt; the &lt;code&gt;PreJoinRoom&lt;/code&gt;, which has a form to join a Daily audio call, depending on our app state.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;InCall&lt;/code&gt; component has the most complexity because it handles our Daily call.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;InCall&lt;/code&gt; contains the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;code&gt;Counter&lt;/code&gt; component, which displays how much time is left in the call&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;CopyLinkBox&lt;/code&gt; to copy and share the room code&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Tray&lt;/code&gt; to control your local microphone, raise your hand, or leave the call&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Participant&lt;/code&gt; component for each participant. It renders:

&lt;ul&gt;
&lt;li&gt;Participant UI, with each participant represented by a box with their initials and a “show more” menu button that renders the &lt;code&gt;Menu&lt;/code&gt; component in certain conditions. (More on that below)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;DailyMenuView&lt;/code&gt; component, which provides the participant’s audio for the call. 
&lt;em&gt;Note: In a React project, you would just render an &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; element.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  CallProvider.jsx: The brain of this operation 🧠
&lt;/h2&gt;

&lt;p&gt;To keep our logic organized and in (mostly) one place, we are using the &lt;a href="https://reactjs.org/docs/context.html" rel="noopener noreferrer"&gt;React Context API&lt;/a&gt;, which helps us store global app state. Our &lt;code&gt;App&lt;/code&gt; component wraps its contents in the &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx" rel="noopener noreferrer"&gt;&lt;code&gt;CallProvider&lt;/code&gt; component&lt;/a&gt; (our context), which means all of our app’s contents can access the data set in our call context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.jsx&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CallProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppContent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/CallProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: The Context API can be used by any React app (not just React Native). In fact, we did just that in the &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx" rel="noopener noreferrer"&gt;web version of this app!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s spend some time understanding what’s happening in &lt;code&gt;CallProvider&lt;/code&gt;. (We can’t cover every detail here, so &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;let us know&lt;/a&gt; if you have questions.) &lt;/p&gt;

&lt;p&gt;There are several actions (i.e. methods) we define in &lt;code&gt;CallProvider&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a new Daily room (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L31" rel="noopener noreferrer"&gt;&lt;code&gt;createRoom&lt;/code&gt;&lt;/a&gt;) with the &lt;a href="https://docs.daily.co/reference/rest-api/rooms/create-room" rel="noopener noreferrer"&gt;Daily REST API&lt;/a&gt;. We’re using a &lt;a href="https://www.netlify.com/products/functions/" rel="noopener noreferrer"&gt;Netlify serverless function&lt;/a&gt; for this but you can use the Daily REST API endpoints however works best for your app.&lt;/li&gt;
&lt;li&gt;Creating a Daily meeting token (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L46" rel="noopener noreferrer"&gt;&lt;code&gt;createToken&lt;/code&gt;&lt;/a&gt;) for meeting moderators with the &lt;a href="https://docs.daily.co/reference/rest-api/meeting-tokens/create-meeting-token" rel="noopener noreferrer"&gt;Daily REST API&lt;/a&gt;. (Same as above regarding using serverless functions.)&lt;/li&gt;
&lt;li&gt;Joining a Daily room (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L65" rel="noopener noreferrer"&gt;&lt;code&gt;joinRoom&lt;/code&gt;&lt;/a&gt;) &lt;/li&gt;
&lt;li&gt;Leaving a room the local participant is currently attending (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L172" rel="noopener noreferrer"&gt;&lt;code&gt;leaveCall&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Muting/unmuting (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L225" rel="noopener noreferrer"&gt;&lt;code&gt;handleMute&lt;/code&gt;, &lt;code&gt;handleUnmute&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Raising/lowering your hand (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L257" rel="noopener noreferrer"&gt;&lt;code&gt;raiseHand&lt;/code&gt;, &lt;code&gt;lowerHand&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L278" rel="noopener noreferrer"&gt;Changing&lt;/a&gt;/getting a participant’s account type (e.g. upgrading a listener to a speaker)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference/rn-daily-js/events" rel="noopener noreferrer"&gt;Adding Daily event listeners&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx#L22" rel="noopener noreferrer"&gt;Initializing app state&lt;/a&gt; that will be shared with other components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Starting with our app state, let’s look at which values we’ll initialize and export to be used throughout our app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CallProvider.jsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CallProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PREJOIN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// pre-join | in-call&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCallFrame&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setParticipants&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRoom&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;roomExp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRoomExp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;activeSpeakerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveSpeakerId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;updateParticipants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUpdateParticipants&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CallContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;
     &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
       &lt;span class="nx"&gt;getAccountType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;changeAccountType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;handleMute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;handleUnmute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;endCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;removeFromCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;raiseHand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;lowerHand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;activeSpeakerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;roomExp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/CallContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How updating a participant type works using &lt;code&gt;sendAppMessage&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In this demo, we manage participant types (moderator, speaker, or listener) by appending a string to the end of each participant’s username, which is not shown in the UI (e.g. &lt;code&gt;${username}_MOD&lt;/code&gt; for moderators).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❗Note: For production-level apps, we recommend building a backend for participant type management. This current solution is meant to keep the code client-side for demo purposes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That said, let’s look at how participant type management works.&lt;/p&gt;

&lt;p&gt;Whenever a moderator updates another participant’s account type, that update will be communicated to other participants with the Daily method &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/send-app-message" rel="noopener noreferrer"&gt;&lt;code&gt;sendAppMessage&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All participants will receive that app message via the &lt;code&gt;app-message&lt;/code&gt; event listener, which is added in &lt;code&gt;CallProvider&lt;/code&gt;: &lt;br&gt;
&lt;code&gt;callFrame.on('app-message', handleAppMessage);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will use the callback method &lt;code&gt;handleAppMessage&lt;/code&gt;, which will update the appended string on the username to the new account type (e.g.&lt;code&gt;_LISTENER&lt;/code&gt; to &lt;code&gt;_SPEAKER&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CallProvider.jsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAppMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[APP MESSAGE]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;MSG_MAKE_MODERATOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[LEAVING]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[REJOINING AS MOD]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

           &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="c1"&gt;// Remove the raised hand emoji&lt;/span&gt;
           &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✋&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✋ &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
             &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
             &lt;span class="na"&gt;moderator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;});&lt;/span&gt;
           &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;MSG_MAKE_SPEAKER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="nf"&gt;updateUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SPEAKER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;MSG_MAKE_LISTENER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="nf"&gt;updateUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LISTENER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;FORCE_EJECT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="c1"&gt;//seeya&lt;/span&gt;
           &lt;span class="nf"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
           &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.05.38.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.05.38.gif" alt="Promoting a listener to speaker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making someone a moderator is slightly more complicated because they need to rejoin the call with a Daily token, which will give them the owner privileges they need to be able to mute other participants. To do this, we kick them out of the call quietly (&lt;code&gt;callFrame.leave()&lt;/code&gt;) and then immediately rejoin them as a moderator with an &lt;a href="https://docs.daily.co/reference/rest-api/meeting-tokens/create-meeting-token" rel="noopener noreferrer"&gt;owner token&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: To make a participant a meeting owner with a meeting token, the &lt;code&gt;is_owner&lt;/code&gt; token property must be &lt;code&gt;true&lt;/code&gt;. See our &lt;a href="https://docs.daily.co/reference/rest-api/meeting-tokens/config" rel="noopener noreferrer"&gt;token configuration docs&lt;/a&gt; for more information.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we go through specific components below, we’ll loop back to some of the other specific methods outlined in &lt;code&gt;CallProvider&lt;/code&gt; as they’re used.&lt;/p&gt;




&lt;h2&gt;
  
  
  PreJoinRoom form
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;PreJoinRoom&lt;/code&gt; component is a form with three inputs (first name, last name, join code), and a button to submit the form. Only the first name is a required field; the last name is optional and if no join code is provided, we take that to mean the user wants to create a new room to join. &lt;/p&gt;

&lt;p&gt;Let’s focus on what happens when you submit the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PreJoinRoom.jsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PreJoinRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;handleLinkPress&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;roomName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRoomName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;submitting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSubmitting&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRequired&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;submitForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setRequired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nf"&gt;setSubmitting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nf"&gt;setRequired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
       &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;roomName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="cm"&gt;/**
        * We track the account type by appending it to the username.
        * This is a quick solution for a demo; not a production-worthy solution!
        */&lt;/span&gt;
       &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;LISTENER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;roomName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;submitForm&lt;/code&gt;, we first make sure the first name is filled out. If not, we update our &lt;code&gt;required&lt;/code&gt; state value, which blocks the form from being submitted.&lt;/p&gt;

&lt;p&gt;Next, we get the local user’s username by joining the first and optional last name values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there’s a room code (&lt;code&gt;roomName&lt;/code&gt;) provided in the form, we assign that to our &lt;code&gt;name&lt;/code&gt; variable and update the username to have &lt;code&gt;_LISTENER&lt;/code&gt; appended to it.&lt;/p&gt;

&lt;p&gt;If there is no room code, we don’t set a room &lt;code&gt;name&lt;/code&gt; and append &lt;code&gt;_MOD&lt;/code&gt; to the username. As mentioned, the person creating the room is the moderator by default so we track that in the name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (roomName?.trim()?.length) {
    name = roomName;

    userName = `${userName}_${LISTENER}`;
} else {
    userName = `${userName}_${MOD}`;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have our &lt;code&gt;userName&lt;/code&gt; and optional room &lt;code&gt;name&lt;/code&gt;, we can then call &lt;code&gt;joinRoom&lt;/code&gt;, a method from &lt;code&gt;CallProvider&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moderator&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;roomInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="cm"&gt;/**
    * The first person to join will need to create the room first
    */&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;moderator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;roomInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;setRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="cm"&gt;/**
    * When a moderator makes someone else a moderator,
    * they first leave and then rejoin with a token.
    * In that case, we create a token for the new mod here.
    */&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moderator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// create a token for new moderators&lt;/span&gt;
     &lt;span class="nx"&gt;newToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCallObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;videoSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// This can be changed to your Daily domain&lt;/span&gt;
     &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://devrel.daily.co/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;roomInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setCallFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
       &lt;span class="nf"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INCALL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;joinRoom&lt;/code&gt; has the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It leaves the current room if you’re somehow already in one. (This is mostly defensive programming for those terrible, horrible, no good, very bad code bug days.)&lt;/li&gt;
&lt;li&gt;It creates a new room with our &lt;code&gt;createRoom&lt;/code&gt; method mentioned above if a room name isn’t provided&lt;/li&gt;
&lt;li&gt;It creates a token if the participant joining is a moderator. This can happen if they are the first person to join &lt;em&gt;or&lt;/em&gt; if they’re rejoining as a moderator after being upgraded&lt;/li&gt;
&lt;li&gt;Next, we create our local Daily call object instance:
&lt;code&gt;const call = Daily.createCallObject({videoSource: false});&lt;/code&gt;
(We’ll go into more detail about the &lt;code&gt;videoSource&lt;/code&gt; property below.)&lt;/li&gt;
&lt;li&gt;We also set our call options that we’ll need before joining the call (room URL being joined, username, and optional token for moderators
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://devrel.daily.co/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; Finally, we join the call and update our local state accordingly, including updating our &lt;code&gt;view&lt;/code&gt; value to &lt;code&gt;incall&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setCallFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="cm"&gt;/**
        * Now mute, so everyone joining is muted by default.
        */&lt;/span&gt;
       &lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INCALL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is complete, we’ll be brought to our &lt;code&gt;InCall&lt;/code&gt; component because of this condition in &lt;code&gt;App.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{view === INCALL &amp;amp;&amp;amp; &amp;lt;InCall handleLinkPress={handleLinkPress} /&amp;gt;}&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The in-call experience: Moderators and the rest of us
&lt;/h2&gt;

&lt;p&gt;Now that we know how to get into a call, let’s focus on how we actually use the &lt;a href="https://github.com/daily-co/react-native-daily-js#readme" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-daily-js&lt;/code&gt;&lt;/a&gt; library to get our audio working. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;InCall&lt;/code&gt; component renders a &lt;code&gt;Participant&lt;/code&gt; component for each participant in the call, and displays them in the UI based on who can speak. Moderators and speakers are shown at the top and listeners are at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.12.43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.12.43.png" alt="Speakers and listeners in-call"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at how we render the &lt;code&gt;Speakers&lt;/code&gt; section, which includes moderators and speakers, i.e. anyone who can unmute themselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// InCall.jsx&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;getAccountType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;]);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;speakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
     &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getAccountType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;SPEAKER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}),&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getAccountType&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The individual participant UI includes details like their name, initials, a star emoji if they’re a moderator, and a “more” menu with some actions depending on their participant type. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.34.32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2FCleanShot-2021-11-12-at-16.34.32.png" alt="Participant UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important aspect of the &lt;code&gt;Participant&lt;/code&gt; component is not visible in the UI, though: the &lt;code&gt;DailyMediaView&lt;/code&gt; component!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Participant.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;DailyMediaView&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@daily-co/react-native-daily-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Participant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;audioTrack&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DailyMediaView&lt;/span&gt;
        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`audio-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a component imported from &lt;code&gt;react-native-daily-js&lt;/code&gt; and accepts audio and/or video tracks from your participants list, also provided by Daily's call object (recall: &lt;code&gt;callObject.participants()&lt;/code&gt;). Since this is an audio-only app, we set &lt;code&gt;videoTrack&lt;/code&gt; to null, and &lt;code&gt;audioTrack&lt;/code&gt; to each participant’s audio track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Participant.jsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
     &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
       &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the audio track is set, you will be able to hear the participant. 👂&lt;/p&gt;

&lt;h3&gt;
  
  
  Sir, this is an Arby’s: Letting moderators mute speakers
&lt;/h3&gt;

&lt;p&gt;Now that we have the audio playing, let’s take a quick look at how we mute participants. &lt;/p&gt;

&lt;p&gt;As mentioned, only participants who joined with an &lt;a href="https://docs.daily.co/reference/rest-api/meeting-tokens/config" rel="noopener noreferrer"&gt;owner meeting token&lt;/a&gt; are permitted to mute others. (And, by the way, we don’t recommend ever letting participants &lt;em&gt;unmute&lt;/em&gt; other participants. It’s a bit invasive! 😬)&lt;/p&gt;

&lt;p&gt;To do this, we can take advantage of Daily’s &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/update-participant" rel="noopener noreferrer"&gt;&lt;code&gt;updateParticipant&lt;/code&gt; method&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;CallProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleMute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[MUTING]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateParticipant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;setAudio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nf"&gt;setUpdateParticipants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`unmute-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here in &lt;code&gt;CallProvider&lt;/code&gt;, we have one &lt;code&gt;handleMute&lt;/code&gt; method for participants to mute themselves or others. If they’re muting themselves, they call &lt;a href="https://docs.daily.co/reference/rn-daily-js/instance-methods/set-local-audio" rel="noopener noreferrer"&gt;&lt;code&gt;setLocalAudio(false)&lt;/code&gt;&lt;/a&gt;. If they’re muting someone else, they call &lt;code&gt;updateParticipant&lt;/code&gt; with the to-be-muted participant’s &lt;code&gt;session_id&lt;/code&gt; and a properties object with &lt;code&gt;setAudio&lt;/code&gt; equal to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  You, you, you, oughta know
&lt;/h2&gt;

&lt;p&gt;One important aspect of audio-only apps to be aware of is device permissions. Since Daily’s React Native library is compatible with audio and video apps, it will ask for microphone &lt;em&gt;and&lt;/em&gt; camera permissions, unless we intervene. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fpermissions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F11%2Fpermissions.png" alt="Device permission requests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t address this issue, your app users will see both of these device permission requests, which may be a bit of a red flag 🚩 for them. (Why would you need camera permissions for an audio app? 🤔)&lt;/p&gt;

&lt;p&gt;To help your apps seem less — well — creepy, you can simply set &lt;code&gt;videoSource&lt;/code&gt; to false when you create the local call object instance. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;const call = Daily.createCallObject({videoSource: false});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Adding this one detail means your users are only asked for microphone permissions. 💫&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;We hope this overview of the Party Line app helps you better understand how it works under the hood. We couldn’t cover every detail, so check out these existing tutorials/resources that cover related topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our &lt;a href="https://www.daily.co/blog/how-to-build-a-billion-dollar-audio-app-in-a-weekend/" rel="noopener noreferrer"&gt;overview of the Party Line project&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Creating &lt;a href="https://www.daily.co/blog/create-audio-only-meetings-with-daily/" rel="noopener noreferrer"&gt;audio-only calls with &lt;code&gt;daily-js&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://www.daily.co/blog/build-a-react-form-to-generate-daily-meeting-tokens/" rel="noopener noreferrer"&gt;tutorial on creating owner meeting tokens&lt;/a&gt; in React&lt;/li&gt;
&lt;li&gt;Our &lt;a href="https://github.com/daily-co/react-native-daily-js-playground" rel="noopener noreferrer"&gt;Playground app repo&lt;/a&gt; in case you’re interested in seeing a React Native video call example&lt;/li&gt;
&lt;li&gt;Building a video or &lt;a href="https://www.daily.co/blog/tutorial-embed-a-daily-video-call-in-any-notion-workspace-page/" rel="noopener noreferrer"&gt;audio-only call embedded in a webpage&lt;/a&gt; via a Chrome extension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our next React Native tutorial, we’ll focus on building a video call app, so stay tuned for that! &lt;/p&gt;

&lt;p&gt;As always, if you have any questions, &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;let us know&lt;/a&gt;! &lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build a custom video chat app with Daily and Vue.js</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Thu, 28 Oct 2021 17:36:50 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-custom-video-chat-app-with-daily-and-vuejs-4952</link>
      <guid>https://dev.to/trydaily/build-a-custom-video-chat-app-with-daily-and-vuejs-4952</guid>
      <description>&lt;p&gt;At Daily, we’ve specifically built our video and audio APIs to be frontend framework-agnostic. This is to make sure developers can implement real-time video calls — a big feature in itself — with whichever JavaScript framework they prefer (or no framework at all).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/hXCJfewTSyqTXz2trM/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/hXCJfewTSyqTXz2trM/giphy.gif" alt="you pick"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We’ve spent a lot of time discussing &lt;a href="https://www.daily.co/blog/building-a-custom-video-chat-app-with-react/" rel="noopener noreferrer"&gt;React demos&lt;/a&gt; and &lt;a href="https://www.daily.co/blog/build-a-real-time-video-chat-app-with-next-js-and-daily/" rel="noopener noreferrer"&gt;sample code&lt;/a&gt; in our blog posts, but &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; is not your only option for a framework. &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt;, for example, is another great option that you can use with &lt;a href="https://github.com/daily-co/daily-js/" rel="noopener noreferrer"&gt;daily-js&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Recently &lt;a href="https://www.daily.co/blog/build-a-video-chat-app-with-vue-and-daily-prebuilt/" rel="noopener noreferrer"&gt;on the blog&lt;/a&gt;, we looked at how to embed &lt;a href="https://daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt; in a Vue app. Daily Prebuilt is our plug-and-play option for video calls, which makes it the fastest and most convenient way to add video to your app.&lt;/p&gt;

&lt;p&gt;In some cases, however, you may need more control over the video call designs, or you might even be building something more custom like an audio-only call app. In cases like these, using Daily’s custom &lt;a href="https://docs.daily.co/call-object" rel="noopener noreferrer"&gt;call object&lt;/a&gt; option gives you total control over the video and audio experience, including the video call design and functionality.&lt;/p&gt;

&lt;p&gt;In today’s tutorial, we’ll look at building a custom video call app in Vue using Daily’s call object.&lt;/p&gt;




&lt;h2&gt;
  
  
  Planning our app’s features
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmz8ah50yqeq5kuuzt52o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmz8ah50yqeq5kuuzt52o.png" alt="Our demo app's home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In terms of functionality, video call participants will be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join the call with video and audio&lt;/li&gt;
&lt;li&gt;Control their own video and microphones while in the call (e.g. to mute themselves)&lt;/li&gt;
&lt;li&gt;Share their screen on any browser that supports screen sharing. We’ll only let one person share at a time to keep things simple for now&lt;/li&gt;
&lt;li&gt;Set their username for the call before joining&lt;/li&gt;
&lt;li&gt;Leave the call whenever they want&lt;/li&gt;
&lt;li&gt;Be notified when device permissions are blocked by the browser, with instructions on how to permit device access&lt;/li&gt;
&lt;li&gt;Communicate via text chat in a custom chat box. (The details for this will be covered in a follow-up post.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fvanujvxyl10jzk1cq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fvanujvxyl10jzk1cq7.png" alt="Our demo app's in-call UI with a single participant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As is required for any app, we also need to manage our feature scope. In this case, we won’t worry about managing large calls in terms of performance optimization or the UI layout. Those are big topics in themselves, as demonstrated by this &lt;a href="https://www.daily.co/blog/tag/large-meeting-series/" rel="noopener noreferrer"&gt;whole series on them&lt;/a&gt;!&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting set up with Daily
&lt;/h2&gt;

&lt;p&gt;To use this demo, you will need a Daily room to join.&lt;/p&gt;

&lt;p&gt;To get your own Daily room URL, you’ll need to &lt;a href="https://dashboard.daily.co/signup" rel="noopener noreferrer"&gt;create a Daily account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have an account and are logged into the &lt;a href="https://dashboard.daily.co" rel="noopener noreferrer"&gt;Daily Dashboard&lt;/a&gt;, you can &lt;a href="https://dashboard.daily.co/rooms/create" rel="noopener noreferrer"&gt;create a new Daily room&lt;/a&gt; and copy its URL.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You can also create Daily rooms via the &lt;a href="https://docs.daily.co/reference/rest-api/rooms" rel="noopener noreferrer"&gt;REST API&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up your local dev environment
&lt;/h2&gt;

&lt;p&gt;As always, we’ve already built this app for you, so — if you like spoilers — feel free to &lt;a href="https://github.com/daily-demos/vue-call-object" rel="noopener noreferrer"&gt;clone and use the demo app via Github&lt;/a&gt;. To run it locally, enter the following commands in your terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn
yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the app at whichever port it’s running, which is likely &lt;code&gt;http://localhost:8080/&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  More spoilers: Looking at our component structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvlwopwnt6e3qpofm333.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvlwopwnt6e3qpofm333.png" alt="component structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s often helpful to know the structure of what we’re going to be building before diving in.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;App&lt;/code&gt; component is our entry point for our Vue app. It will always render the &lt;code&gt;AppHeader&lt;/code&gt; component and conditionally render either &lt;code&gt;Call&lt;/code&gt; or  &lt;code&gt;Home&lt;/code&gt;, depending on whether the user has joined a call.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Call&lt;/code&gt; is where &lt;code&gt;daily-js&lt;/code&gt; will be imported, and where all the call’s logic will be defined. It is also the parent component for the rest of the components in the app. &lt;/p&gt;

&lt;p&gt;Let’s briefly define what each of these components does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Loading&lt;/code&gt;: This component contains an &lt;code&gt;svg&lt;/code&gt; with a loading animation. It shows when the user is joining a call, (i.e. in a loading state).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VideoTile&lt;/code&gt;: This component is rendered for each participant in the call. It will either render a &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element or a &lt;code&gt;NoVideoTile&lt;/code&gt; component depending on whether the participant has their video on. An  tag is rendered for each participant. For local participants, &lt;code&gt;Controls&lt;/code&gt; is also a child component of the &lt;code&gt;VideoTile&lt;/code&gt;. That means everyone gets device controls for their own tile. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WaitingCard&lt;/code&gt;: If you are alone in a call, this component is rendered to let you know you are waiting for others to join.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ScreenshareTile&lt;/code&gt;: When a screen share is started, this component is added for the screen share track.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PermissionsErrorMsg&lt;/code&gt;: If camera or microphone permissions are blocked locally, this card is rendered instead of the call view so you know to update your browser permissions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Chat&lt;/code&gt;: This is where our chat messages will be sent and displayed. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s see how these actually work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking advantage of Vue’s data object
&lt;/h2&gt;

&lt;p&gt;One thing you might notice looking at the code for this demo is that there’s no state management library or dedicated backend; instead, we rely on &lt;a href="https://v3.vuejs.org/api/options-data.html" rel="noopener noreferrer"&gt;Vue’s data object&lt;/a&gt; to keep any information handy that needs to be referenced throughout the code base.&lt;/p&gt;

&lt;p&gt;As you review each component in the rest of this tutorial, be sure to look at each component’s &lt;code&gt;data&lt;/code&gt; method to see which values are being stored.&lt;/p&gt;




&lt;h2&gt;
  
  
  Okay, get to the code already
&lt;/h2&gt;

&lt;p&gt;Now that we know what we’re building, we can actually start coding it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;App&lt;/code&gt; component: Determining our in-call state
&lt;/h3&gt;

&lt;p&gt;The main conditional we have in &lt;code&gt;App&lt;/code&gt; is whether to show our home screen or the call UI. &lt;/p&gt;

&lt;p&gt;The home screen is the default view when you visit the demo site. It renders a form to join a specific Daily room. The call UI is everything you see once you submit the form on the home screen to join a Daily room.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-26-at-14.55.15.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-26-at-14.55.15.gif" alt="joining a call"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;App&lt;/code&gt;’s template, we represent this conditional by checking the value of &lt;code&gt;appState&lt;/code&gt;, a value on our data object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;
   &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appState === 'incall'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveCall&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
 &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;joinCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joinCall&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;appState&lt;/code&gt; equals &lt;code&gt;incall&lt;/code&gt;, we show our &lt;code&gt;Call&lt;/code&gt; component; otherwise, we render our &lt;code&gt;Home&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Looking at the data object and methods in &lt;code&gt;App&lt;/code&gt;, the &lt;code&gt;appState&lt;/code&gt; is initially set to &lt;code&gt;idle&lt;/code&gt; on render. When you join a call through the home screen’s form, &lt;code&gt;appState&lt;/code&gt; gets set to &lt;code&gt;incall&lt;/code&gt;. Any time the call is left or refreshed, &lt;code&gt;appState&lt;/code&gt; gets reset to &lt;code&gt;idle&lt;/code&gt;, bringing the local user back to the home screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;appState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Guest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;joinCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;incall&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="nf"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;joinCall&lt;/code&gt; gets called in &lt;code&gt;Home&lt;/code&gt; and passes the two input values (&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;) as function parameters. These are then set in &lt;code&gt;App&lt;/code&gt;’s data object and will get passed as props to &lt;code&gt;Call&lt;/code&gt; to be used later by &lt;code&gt;daily-js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is really all that happens in &lt;code&gt;App&lt;/code&gt; and &lt;code&gt;Home&lt;/code&gt;, so let’s jump right to &lt;code&gt;Call&lt;/code&gt; to understand how our video call functionality works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video call the radio star: Letting participants join with video and audio
&lt;/h3&gt;

&lt;p&gt;When using Daily’s &lt;a href="https://docs.daily.co/call-object" rel="noopener noreferrer"&gt;call object&lt;/a&gt; like we are in this demo, we need to manually add any elements we want present in our UI. (This is in contrast to &lt;a href="https://daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt;, where it’s all done for you.)&lt;/p&gt;

&lt;p&gt;That means we’ll need to handle the following in our &lt;code&gt;Call&lt;/code&gt; component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; elements for any call participants who might have video or audio on. (In this demo, that’s everyone who joins.)

&lt;ul&gt;
&lt;li&gt;If someone turns off their video, we’ll show a placeholder to avoid shifting the layout when video isn’t available.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.27.01.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.27.01.gif" alt="toggling video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element specifically for screen shares. &lt;/li&gt;
&lt;li&gt;Adding a control panel for the local participant to toggle their camera and microphone, share their screen, or leave the call.&lt;/li&gt;
&lt;li&gt;We’ll also add some basic styling for group call layout management, though we’ll prioritize one-on-one calls to keep our CSS styles simpler to start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step in the &lt;code&gt;Call&lt;/code&gt; component is to initialize the call instance with &lt;code&gt;daily-js&lt;/code&gt; and to join the call, so let’s look at what happens when the &lt;code&gt;Call&lt;/code&gt; component is mounted in the &lt;code&gt;mounted()&lt;/code&gt; lifecycle method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
     &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;showPermissionsError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="nf"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

   &lt;span class="c1"&gt;// Create instance of Daily call object&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;co&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;daily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCallObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Assign in data obj for future reference&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;co&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// Join the call with the name set in the Home.vue form&lt;/span&gt;
   &lt;span class="nx"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="c1"&gt;// Add call and participant event handler&lt;/span&gt;
   &lt;span class="c1"&gt;// Visit https://docs.daily.co/reference/daily-js/events for more event info&lt;/span&gt;
   &lt;span class="nx"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleJoiningMeeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-updated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="c1"&gt;// camera-error = device permissions issue&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;camera-error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleDeviceError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="c1"&gt;// app-message handles receiving remote chat messages&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateMessages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our three major tasks in the &lt;code&gt;mounted&lt;/code&gt; method is to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Initialize a new Daily call object using the Daily URL provided in the home screen form&lt;br&gt;
&lt;code&gt;const option = { url: this.roomUrl };&lt;/code&gt;&lt;br&gt;
&lt;code&gt;const co = daily.createCallObject(option);&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Join the Daily call using the username also provided in the home screen form&lt;br&gt;
&lt;code&gt;co.join({ userName: this.name });&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add our &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events" rel="noopener noreferrer"&gt;Daily event&lt;/a&gt; listeners to know when to update our call UI.&lt;br&gt;
&lt;code&gt;co.on("joining-meeting", this.handleJoiningMeeting)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;...&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Daily events and their callbacks
&lt;/h2&gt;

&lt;p&gt;Before moving on, let’s look at each of the callbacks attached to the Daily events mentioned above to understand how they impact our app’s state.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#joining-meeting" rel="noopener noreferrer"&gt;&lt;code&gt;joining-meeting&lt;/code&gt;&lt;/a&gt; event
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;joining-meeting&lt;/code&gt; gets called when the local participant is still joining the call. This is like a loading state before being officially in the call.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;co.on("joining-meeting", this.handleJoiningMeeting)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;handleJoiningMeeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;handleJoiningMeeting&lt;/code&gt; callback, we set &lt;code&gt;loading&lt;/code&gt; in our data object to true so we know when to show our loading spinner in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#joined-meeting" rel="noopener noreferrer"&gt;&lt;code&gt;joined-meeting&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.daily.co/reference/daily-js/events/participant-events#participant-joined" rel="noopener noreferrer"&gt;&lt;code&gt;participant-joined&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.daily.co/reference/daily-js/events/participant-events#participant-updated" rel="noopener noreferrer"&gt;&lt;code&gt;participant-updated&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.daily.co/reference/daily-js/events/participant-events#participant-left" rel="noopener noreferrer"&gt;&lt;code&gt;participant-left&lt;/code&gt;&lt;/a&gt; events
&lt;/h3&gt;

&lt;p&gt;In this demo, we keep an array of the current participants in our data object to iterate through in our UI. That means we need to update our participant list whenever the participants have an event that will affect our list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-updated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participant-left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All four of these events are handled by the same callback, &lt;code&gt;updateParticipants(e)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In apps with large meetings, you will likely need to set up separate methods for these events to avoid any unnecessary re-renders.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;updateParticpants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenVideoTrack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we get all the participants from the Daily call object with the &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/participants" rel="noopener noreferrer"&gt;&lt;code&gt;participants()&lt;/code&gt; method&lt;/a&gt; and convert it from an object to an array. We also assign that array to our &lt;code&gt;participants&lt;/code&gt; key in the data object for future reference.&lt;/p&gt;

&lt;p&gt;If any participants have a &lt;code&gt;screenVideoTrack&lt;/code&gt;, it means they are screen sharing. We then set the screen share in our data object to be accessed in our HTML. &lt;/p&gt;

&lt;p&gt;Lastly, we make sure we’re not in a loading state, which is technically only necessary the first time this method gets called.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#error" rel="noopener noreferrer"&gt;&lt;code&gt;error&lt;/code&gt;&lt;/a&gt; event
&lt;/h3&gt;

&lt;p&gt;This is only called if the video call gets stuck in an unrecoverable state. In an ideal world, it would never get called, but like all good programmers, we cover every possibility. 😇&lt;/p&gt;

&lt;p&gt;&lt;code&gt;co.on("error", this.handleError)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errorMsg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we set our &lt;code&gt;error&lt;/code&gt; data object key to the error message provided by &lt;code&gt;daily-js&lt;/code&gt; and make sure we’re not in a loading state.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#camera-error" rel="noopener noreferrer"&gt;&lt;code&gt;camera-error&lt;/code&gt;&lt;/a&gt; event
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;daily-js&lt;/code&gt; to access call participants’ devices (like their camera and microphone), it requires that call participants give it explicit browser permissions. Without these permissions (either at the start of a call or mid-call), the &lt;code&gt;camera-error&lt;/code&gt; event will get triggered. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;co.on("camera-error", this.handleDeviceError)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;handleDeviceError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showPermissionsError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a &lt;code&gt;camera-error&lt;/code&gt; (i.e. device error) happens, we update the data object so that &lt;code&gt;showPermissionError&lt;/code&gt; is true. This will let us know when to tell our local participant to update their permission settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;a href="https://docs.daily.co/reference/daily-js/events/meeting-events#app-message" rel="noopener noreferrer"&gt;&lt;code&gt;app-message&lt;/code&gt;&lt;/a&gt; event
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;co.on("app-message", this.updateMessages);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app-message&lt;/code&gt; gets called when a participant sends a message in the call via the &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/send-app-message" rel="noopener noreferrer"&gt;&lt;code&gt;sendAppMessage()&lt;/code&gt; Daily instance method&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;updateMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll discuss how chat works in more detail in a follow-up post, but for now it’s important to know every chat message sent by a call participant is saved to the &lt;code&gt;messages&lt;/code&gt; array in the data object. That array can then be iterated over to display our full chat history in the chat box.&lt;/p&gt;

&lt;h2&gt;
  
  
  How our stored data impacts our rendered &lt;code&gt;Call&lt;/code&gt; UI
&lt;/h2&gt;

&lt;p&gt;Each of these values we set in the data object are used to conditionally render different views in our call UI.&lt;/p&gt;

&lt;p&gt;To start, let’s look our &lt;code&gt;Call&lt;/code&gt;’s template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;meeting&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading-spinner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;refreshing&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;leave&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-button &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="nx"&gt;Refresh&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;showPermissionsError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
           &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen ? 'tile-container' : 'tile-container full-height'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;screenshare&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participants-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p in participants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p.session_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleVideoClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleVideoClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleAudioClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleAudioClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                 &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;disableScreenShare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen &amp;amp;&amp;amp; !screen?.local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
               &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count === 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;waiting&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sendMessage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are quite a few conditions here, so let’s break it down a bit.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;loading&lt;/code&gt; is true, we show a loading spinner, whereas when &lt;code&gt;loading&lt;/code&gt; is false, we show the call UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading-spinner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-21-at-17.20.36.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-21-at-17.20.36.gif" alt="loading spinner while joining call"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Next, once we’ve officially joined the call, we conditionally show an error message and refresh button when &lt;code&gt;error&lt;/code&gt; is truthy. This is so the local participant can refresh the page if something goes wrong. 😬&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;refreshing&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;leave&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-button &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Refresh&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&amp;gt;&amp;lt;template v-if="error"&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;refreshing&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;leave&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-button &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Refresh&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we want to show a message in our UI if the device permissions are blocked. In some cases, you may not want to prevent your users from seeing the video call just because their permissions are blocked, but we do because we consider device permissions a requirement to use this app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;showPermissionsError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23lxble5t3g94l44juxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23lxble5t3g94l44juxp.png" alt="Blocked device permissions message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterating over our participants array
&lt;/h3&gt;

&lt;p&gt;The next block of elements in our template is where we render actual video tiles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen ? 'tile-container' : 'tile-container full-height'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;screenshare&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participants-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;participants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p in participants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p.session_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleVideoClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleVideoClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleAudioClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleAudioClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;disableScreenShare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen &amp;amp;&amp;amp; !screen?.local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count === 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;waiting&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first section here renders a screen share tile anytime &lt;code&gt;screen&lt;/code&gt; is truthy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;screenshare&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we render a &lt;code&gt;VideoTile&lt;/code&gt; component for each participant in our &lt;code&gt;participants&lt;/code&gt; array on the data object and pass any relevant information as a prop to be used in that component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p in participants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p.session_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tile&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleVideoClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleVideoClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleAudioClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleAudioClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handleScreenshareClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveAndCleanUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;disableScreenShare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screen &amp;amp;&amp;amp; !screen?.local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we render an extra card if there’s only one participant so they don’t feel lonely while waiting. 👯&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count === 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;waiting&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The very last component that gets rendered in our call UI is the &lt;code&gt;Chat&lt;/code&gt; component, which is included whenever you have officially joined the call. It handles sending and displaying chat messages.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;chat :sendMessage="sendMessage" :messages="messages" /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.06.17.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.06.17.gif" alt="toggling the chat component"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;That was a lot to go through, but we now officially have all our call UI included in our app! 💪&lt;/p&gt;

&lt;p&gt;Our next steps will be to take a closer look at &lt;code&gt;VideoTile&lt;/code&gt; and &lt;code&gt;ScreenshareTile&lt;/code&gt; to see how we turn the media tracks provided by &lt;code&gt;daily-js&lt;/code&gt; into actual video tiles in our app. &lt;/p&gt;

&lt;h2&gt;
  
  
  Call me a mason because we’re about to lay some tiles
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;VideoTile&lt;/code&gt; component is rendered for each participant and includes an &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; element and a &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element (or &lt;code&gt;NoVideoTile&lt;/code&gt; placeholder component). For the local participant, it also renders the &lt;code&gt;Controls&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folnlvm7gtjyeovw7u77s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folnlvm7gtjyeovw7u77s.png" alt="Controls in the video tile UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;VideoTile&lt;/code&gt; mounts, we do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;videoSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;audioSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Guest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="nf"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set the username in our data object so we can display it in our tile UI&lt;/li&gt;
&lt;li&gt;Handle updating the video and audio elements with the tracks for this tile’s participant
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;handleVideo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;persistentTrack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaStream&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the participant’s video playing in the component’s &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element, we need to create a new &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/MediaStream" rel="noopener noreferrer"&gt;&lt;code&gt;MediaStream&lt;/code&gt;&lt;/a&gt;by passing the participant’s video &lt;a href="https://docs.daily.co/reference/daily-js/instance-methods/participants#participant-properties" rel="noopener noreferrer"&gt;&lt;code&gt;persistentTrack&lt;/code&gt;&lt;/a&gt; and setting that as the &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;’s &lt;code&gt;srcObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the participant’s audio, we do the same thing but with the participant’s audio &lt;code&gt;persistentTrack&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;handleAudio&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;persistentTrack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;persistentTrack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaStream&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that is managed, we can toggle our video and audio using the controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a &lt;code&gt;ScreenshareTile&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;ScreenshareTile&lt;/code&gt; is almost identical to the regular &lt;code&gt;VideoTile&lt;/code&gt;, except it uses the &lt;code&gt;screenVideoTrack&lt;/code&gt; instead of a &lt;code&gt;persistentTrack&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;handleVideo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoTrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;screenVideoTrack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaStream&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.32.25.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F10%2FCleanShot-2021-10-22-at-15.32.25.gif" alt="Starting and stopping a screen share"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve set up the &lt;code&gt;ScreenshareTile&lt;/code&gt; to always show on top of the participants’ tiles, but how you want to style it is completely up to you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If you’re wondering about how &lt;code&gt;Chat&lt;/code&gt; works, we’ll be sharing a follow up post soon that will do a deeper dive into how to quickly build the custom chat box included in this demo. &lt;/p&gt;

&lt;p&gt;And, remember, this demo is just a jumping off point for all the custom UI you can build for video or audio-only apps using Daily’s &lt;a href="https://docs.daily.co/call-object" rel="noopener noreferrer"&gt;call object mode&lt;/a&gt;. It really can be as creative and custom as you’d like.&lt;/p&gt;

&lt;p&gt;If you want to expand on this app even more, you could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;a href="https://www.daily.co/blog/build-your-own-prejoin-call-ui-in-a-custom-daily-video-chat-app/" rel="noopener noreferrer"&gt;prejoin UI&lt;/a&gt; to test devices and see your local video before joining&lt;/li&gt;
&lt;li&gt;Allow users to create rooms via the app UI using Daily's &lt;a href="https://docs.staging.daily.co/reference/rest-api/rooms" rel="noopener noreferrer"&gt;REST API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Manage meeting permissions via &lt;a href="https://docs.staging.daily.co/guides/controlling-who-joins-a-meeting" rel="noopener noreferrer"&gt;room settings&lt;/a&gt;, like making the call a &lt;a href="https://www.daily.co/blog/daily-prebuilt-broadcast-call-deep-dive/" rel="noopener noreferrer"&gt;broadcast call&lt;/a&gt;. (Time for a &lt;a href="https://www.daily.co/blog/tag/webinar/" rel="noopener noreferrer"&gt;webinar&lt;/a&gt;, anyone? 😊)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>video</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Designing web accessible video calls</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Thu, 16 Sep 2021 21:23:46 +0000</pubDate>
      <link>https://dev.to/trydaily/designing-web-accessible-video-calls-3852</link>
      <guid>https://dev.to/trydaily/designing-web-accessible-video-calls-3852</guid>
      <description>&lt;h2&gt;
  
  
  Tips from Daily on how we implement accessible UIs to ensure everyone can connect online through video
&lt;/h2&gt;

&lt;p&gt;A major goal of ours at Daily is to build video and audio APIs that work for as many people as possible. This means not only building high quality APIs, but also building UIs (user interfaces) that accommodate more than just an imaginary “average user”; we want &lt;a href="https://daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt;, our &lt;a href="https://dashboard.daily.co/" rel="noopener noreferrer"&gt;Dashboard&lt;/a&gt;, and our &lt;a href="https://docs.daily.co/" rel="noopener noreferrer"&gt;docs&lt;/a&gt; to be accessible to everyone.&lt;/p&gt;

&lt;p&gt;One way we’ve worked towards this at Daily is to build our UIs following web accessibility standards from the start. Internally, we use a component library with components that have all been built to meet &lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/" rel="noopener noreferrer"&gt;these basic standards&lt;/a&gt;, which means all of our UIs using this library have accessibility baked in. 🍞 &lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll review web accessibility basics, and take a look at how we’ve implemented web accessibility in Daily’s own UIs. We know a site's accessibility can almost always be improved — and this is something we’re committed to working on continuously. However, if you’re building video apps for the first time (or even the second or third), we hope that some of the steps we’ve taken can inspire your own designs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Web accessibility: What exactly is it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.w3.org/WAI/planning-and-managing/initiate/#learn-the-basics" rel="noopener noreferrer"&gt;Web accessibility&lt;/a&gt; refers to making website information and interactions available to everyone, regardless of barriers, such as disability, geography, language, device restrictions, and more. These barriers may be temporary, such as a broken arm, or permanent, such as a visual impairment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The term “accessibility” is sometimes written as “a11y”, which is a numeronym. (There are 11 letters between the first letter (“a”) and last letter (“y”). Hence, a11y. 😉)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Who benefits from web accessibility?
&lt;/h2&gt;

&lt;p&gt;In terms of who web accessibility is for, it truly benefits everyone. We want to emphasize that because even people who don’t &lt;em&gt;require&lt;/em&gt; accessible websites still benefit from them. 🙌&lt;/p&gt;

&lt;p&gt;Accessible websites are often just better designed websites. Basic accessibility guidelines—like making sure your font size is large enough or your colour palette is high contrast enough—make the website easier for everyone to understand.&lt;/p&gt;

&lt;p&gt;However, when accessibility is not considered, there are often specific groups of people who are affected most. &lt;a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/" rel="noopener noreferrer"&gt;This includes people with&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cognitive impairments (e.g. memory impairments)&lt;/li&gt;
&lt;li&gt;Neurological disorders (e.g. Parkinson’s)&lt;/li&gt;
&lt;li&gt;Physical, visual, auditory, or speech impairments (e.g. colour blindness, reduction in fine motor skills)&lt;/li&gt;
&lt;li&gt;Temporary impairments (e.g. broken arm)&lt;/li&gt;
&lt;li&gt;Poor network conditions (e.g. slow page load times)&lt;/li&gt;
&lt;li&gt;Small or old devices (e.g. reduced CPU capacity)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  POUR Principles
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org/TR/UNDERSTANDING-WCAG20/intro.html" rel="noopener noreferrer"&gt;WCAG (Web Content Accessibility Guidelines)&lt;/a&gt; outline four principles for web accessibility, also known as the POUR principles. These principles are incredibly useful for testing whether a website meets the goals set out by &lt;a href="https://www.w3.org/WAI/standards-guidelines/" rel="noopener noreferrer"&gt;web accessibility standards&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;POUR is an acronym for perceivable, operable, understandable, and robust. These principles represent the following goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Perceivable&lt;/em&gt;: Websites should be perceivable, i.e. available to the senses, such as vision, touch, and hearing.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Operable&lt;/em&gt;: Users can interact with any elements on a webpage that are meant to be interacted with regardless of the device they’re using (e.g. mouse, keyboard, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Understandable&lt;/em&gt;: Websites should be easy to understand regardless of how they’re read (e.g. visually, screen reader, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Robust&lt;/em&gt;: Websites should maximize how compatible they are with various browsers, devices, operating systems, network conditions, etc.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Web Accessibility at Daily
&lt;/h2&gt;

&lt;p&gt;Now that we’ve done a quick overview of what web accessibility is, let’s take a look at some of the ways Daily has made its UIs accessible. This is not a complete list of how we incorporate accessibility into Daily products, but we hope this helps give some inspiration with your own apps!&lt;/p&gt;

&lt;p&gt;The list we’ll cover today includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making all UI elements keyboard-accessible, including how we use focus traps and avoid keyboard traps to enhance keyboard navigation&lt;/li&gt;
&lt;li&gt;Adding skip links in Daily’s Dashboard&lt;/li&gt;
&lt;li&gt;Special treatment of “hidden” elements&lt;/li&gt;
&lt;li&gt;Using semantic HTML&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Making all interactive UI elements keyboard-accessible
&lt;/h2&gt;

&lt;p&gt;One of the most effective ways to make websites more accessible is to make sure your audience can always interact with your site without a mouse. The idea is to make sure any element on the page that can be interacted with can be interacted with in multiple ways, whether it be a keyboard, mouse, or other device.&lt;/p&gt;

&lt;p&gt;This means the site visitor should be able to tab through elements, submit forms or inputs, or escape optional views, like modals, without using a mouse. &lt;/p&gt;

&lt;p&gt;In the example below, notice how a participant can join a call and move through Daily Prebuilt’s video call UI only with a keyboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.07.03.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.07.03.gif" alt="Tabbing through Daily Prebuilt video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is ideal because we never want site visitors to feel like they can’t join a call or, worse, can’t leave a call once they’ve joined. No one should ever feel “stuck” moving through the user flow.&lt;/p&gt;

&lt;p&gt;If you’re curious what tabbing through a Daily call is like with a screen reader, watch this example below, which is using a &lt;a href="https://chrome.google.com/webstore/detail/screen-reader/kgejglhpjiefppelpmljglcjbhoiplfn/related?hl=en" rel="noopener noreferrer"&gt;screen reader Chrome extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mtV9RSeI05o"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding focus traps
&lt;/h3&gt;

&lt;p&gt;Another way of helping non-mouse users is to include focus traps in your websites.&lt;/p&gt;

&lt;p&gt;Focus traps refer to traps (or loops) of focusable elements within a parent element on the page. A common example of when to use this is with a modal. When a site visitor opens a modal, if they tab through the contents of the modal and get to the end, tabbing again should bring the user back to the first tabbable element in the modal. This is in contrast to another, less accessible option: continuing to tab to the next element in the DOM—past the modal— while the modal is still open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.07.03.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.07.03.gif" alt="Tabbing through Settings modal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason focus traps are useful is because we can assume while the modal is open, the modal is the only element the visitor is trying to interact with until they close it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Avoiding keyboard traps
&lt;/h3&gt;

&lt;p&gt;Wait, are “traps” bad or good? Well, it depends! We now know why focus traps are good for accessibility, but is there ever a time where trapping the focus is bad?&lt;/p&gt;

&lt;p&gt;You can probably tell from the name of this section: yes!&lt;/p&gt;

&lt;p&gt;A “keyboard trap” refers to when an element can be focused but can’t be unfocused. The site visitor gets trapped on an element if they’re only using a keyboard. Since some users can’t use a mouse, any action a site visitor takes with a keyboard should be able to be undone. &lt;/p&gt;

&lt;p&gt;An example of this is if you open a modal to change your username in a Daily call. &lt;/p&gt;

&lt;p&gt;In this first example below, we see a modal with a username form and one button to change the name. If I’m only using a keyboard, there’s no button to close the modal or cancel changing my name. If the keyboard’s &lt;code&gt;Escape&lt;/code&gt; key doesn’t close the modal either, I’ll have to fill out the form to get back to the video call. This is what we don’t want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4m0y33urz0dbhb7dmmcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4m0y33urz0dbhb7dmmcj.png" alt="Bad example of a modal with no way out"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s compare that scenario to how Daily Prebuilt’s username form is actually set up: The modal can be closed with a keyboard’s &lt;code&gt;Escape&lt;/code&gt; key or by pressing the &lt;code&gt;Cancel&lt;/code&gt; button. The call participant is never forced to change their username if the username modal has been opened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3ty2tktij2wa2pwdqm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3ty2tktij2wa2pwdqm8.png" alt="Better example of a modal with a cancel button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding skip links to Daily’s Dashboard
&lt;/h2&gt;

&lt;p&gt;Another web accessibility feature that can help non-mouse users a lot is to add skip links to websites with navigation bars or a lot of links in the header. Skip links are links that are styled to be off screen unless they’re tabbed to, which means you don’t see them if you’re using a mouse.&lt;/p&gt;

&lt;p&gt;You can include more than one skip link; ideally, you want to give site visitors the option of skipping to whichever section of the page they may want to jump to without having to tab through the entire page.&lt;/p&gt;

&lt;p&gt;As an example of this, let’s look at Daily’s Dashboard. If you’re looking at the &lt;a href="https://dashboard.daily.co/recordings" rel="noopener noreferrer"&gt;Recordings page&lt;/a&gt; and want to get to the &lt;code&gt;Learn how to retrieve rtp-tracks recordings&lt;/code&gt; link, you have to tab through the header and nav bar to get to the main content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.20.47.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.20.47.gif" alt="Tabbing through Dashboard header and nav"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make this easier to navigate by keyboard, we can add two skip links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Skip to navigation&lt;/code&gt; to avoid having to tab through the header&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Skip to main&lt;/code&gt; to avoid tabbing through the header and nav bar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we are already on the &lt;code&gt;Recordings&lt;/code&gt; page in the example below, we can skip right to the main content with one tab and open that first link. 🎊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.25.11-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F09%2FCleanShot-2021-09-01-at-11.25.11-1.gif" alt="Using skip links to skip to main content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create these skip links in the Daily Dashboard, we added two anchor tags to the top of our Dashboard header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"skip-link"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     Skip to main content
   &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

   &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"skip-link"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     Skip to navigation
   &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we style them to not show by default and instead only show when they are being focused on. We do this by clipping the links to be 1 x 1px, and updating the &lt;code&gt;clip&lt;/code&gt; property only when they’re focused.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.skip-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.skip-link&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we add an id attribute (&lt;code&gt;#main&lt;/code&gt; and &lt;code&gt;#nav&lt;/code&gt;) to the associated elements so clicking the link (the anchor tag) brings the focus to that part of the page. The end result is that all the content between the link and the target (i.e. the header and the nav bar) gets skipped in the tab order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Special treatment of “hidden” elements
&lt;/h2&gt;

&lt;p&gt;Along the same lines of skip links, there are other times when an element may be off screen. One example is when icons are used for buttons and we want screen readers to know how to interpret them, as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating hidden labels for screen readers
&lt;/h3&gt;

&lt;p&gt;The way we handle this at Daily is by using a &lt;code&gt;&amp;lt;VisuallyHidden&amp;gt;&lt;/code&gt; React component in the button contents, which is really just a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; with text that is styled to not be visible. This means the screen reader can read it but site visitors who can visually see the UI will just see the icon.&lt;/p&gt;

&lt;p&gt;It’s important to note when you are visually hiding an element meant for a screen reader, you should not use &lt;code&gt;visible:hidden;&lt;/code&gt; or &lt;code&gt;display:none;&lt;/code&gt;. Both of these CSS properties will hide the element visually &lt;em&gt;and&lt;/em&gt; hide it from a screen reader, which is not what we want.&lt;/p&gt;

&lt;p&gt;Instead, like in the previous skip link example, we want to style it to only not be visually shown. There are a few ways to do this, so let’s look at how we hide text in Daily’s component library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VisuallyHidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="nx"&gt;jsx&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`
     span {
       clip: rect(1px, 1px, 1px, 1px);
       height: 1px;
       overflow: hidden;
       position: absolute;
       white-space: nowrap;
       width: 1px;
     }
   `&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/style&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to the skip link, we clip the &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; to be 1 x 1px and hide any overflowing content. This successfully prevents the text from being seen while still letting the screen reader read it.&lt;/p&gt;

&lt;p&gt;Our &lt;a href="https://docs.daily.co/reference#properties" rel="noopener noreferrer"&gt;Daily Prebuilt full screen button&lt;/a&gt; is one example where this &lt;code&gt;&amp;lt;VisuallyHidden&amp;gt;&lt;/code&gt; component is used. Since it is just a full screen icon in the Prebuilt UI, we add text to make it more descriptive for a screen reader.&lt;/p&gt;

&lt;p&gt;To ensure it can be read properly by screen readers, a span with the text  “Enter full screen” is included in the HTML but not shown in the UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21vcd9wjaxr8a65gjzc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21vcd9wjaxr8a65gjzc5.png" alt="DOM shows span that isn't visible in the call UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing hidden elements from the tab order
&lt;/h3&gt;

&lt;p&gt;Another example of special treatment of hidden elements is removing an element from the tab order if it is in the DOM but the site visitor is not meant to be aware of it.&lt;/p&gt;

&lt;p&gt;For example, tooltips included in Daily Prebuilt are not shown unless hovered over. These tooltips don’t need to be read by the screen reader while the call participant tabs through the call elements because the buttons they’re related to are already being described by the screen reader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tooltip&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ctrlKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; + D`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;tabIndex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TrayButton&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleMic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MicrophoneIcon&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;buttonText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/TrayButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Tooltip&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we can remove the tooltip from the tab order with the attribute &lt;code&gt;tabindex=”-1”&lt;/code&gt;. This will prevent the tooltip from getting keyboard focus, which will prevent the screen reader from reading the tooltip’s text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using semantic HTML
&lt;/h2&gt;

&lt;p&gt;One of the most basic ways we’re committed to accessibility at Daily is using semantic HTML.&lt;/p&gt;

&lt;p&gt;Semantic HTML refers to HTML elements that describe the element content. For example, if you are building a web form, writing the form with semantic HTML would use a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag, with an &lt;code&gt;&amp;lt;input type=”submit”&amp;gt;&lt;/code&gt; at the end to submit the form. In essence, you always want to use the element that represents what the element actually is (such as a &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, a &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;, an unordered list &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;, etc.) This is in contrast to using non-semantic HTML, which would use a vaguer container element, like a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Semantic HTML helps communicate to the browser (and developer reading the code!) what each section of your markup is. This also makes it easier for screen readers to understand how to read the page’s content to its listener, and it makes the page more SEO-friendly. &lt;/p&gt;

&lt;p&gt;It's win-win for everyone!&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;As mentioned, these examples are just a few ways our frontend team at Daily—&lt;a href="https://www.daily.co/blog/author/christian/" rel="noopener noreferrer"&gt;Christian&lt;/a&gt;, especially—is ensuring Daily products are accessible to everyone. We still have some areas to improve, but we do our best to ensure our product UIs are accessible at launch. 💫&lt;/p&gt;

&lt;p&gt;Some additional tips we didn’t have space to go into include always labelling form inputs, testing color palettes to meet &lt;a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer"&gt;color contrast requirements&lt;/a&gt;, and actually testing websites with screen reader tools, like a &lt;a href="https://developer.chrome.com/docs/devtools/accessibility/reference/" rel="noopener noreferrer"&gt;screen reader Chrome extension&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Testing with screen reader extensions are not only useful for developers, but they also help show what it’s really like to rely on a screen reader to navigate the web. If you’ve never used a screen reader before, &lt;a href="https://twitter.com/kentcdodds/status/1083073242330361856" rel="noopener noreferrer"&gt;check out this example&lt;/a&gt; of how frustrating it can be when people use special characters unnecessarily.&lt;/p&gt;

&lt;p&gt;Another area we didn’t touch on is optimizing site performance to help those with CPU or internet restrictions. Check out our &lt;a href="https://www.daily.co/blog/tips-to-improve-performance/" rel="noopener noreferrer"&gt;previous post on improving video call performance&lt;/a&gt; to learn some quick ways to make your custom Daily calls easier to load.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>javascript</category>
      <category>css</category>
    </item>
    <item>
      <title>Build a real-time video chat app with Vue and Daily Prebuilt in under ten minutes</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Mon, 30 Aug 2021 17:54:37 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-video-chat-app-with-vue-and-daily-prebuilt-2onb</link>
      <guid>https://dev.to/trydaily/build-a-video-chat-app-with-vue-and-daily-prebuilt-2onb</guid>
      <description>&lt;p&gt;At Daily, we’ve spent a lot of time making sure our video and audio-only APIs can be used with any frontend framework, or no framework at all. 🍦 It’s important to us to make flexible APIs that can be incorporated into any app looking to add audio and video chat. We’ve created several demos for our customers using &lt;a href="https://github.com/daily-demos/prebuilt-ui" rel="noopener noreferrer"&gt;plain JavaScript&lt;/a&gt;, &lt;a href="https://github.com/daily-demos/call-object-react" rel="noopener noreferrer"&gt;React&lt;/a&gt;, &lt;a href="https://github.com/daily-demos/examples" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, &lt;a href="https://github.com/daily-demos/party-line" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;, &lt;a href="https://github.com/daily-demos" rel="noopener noreferrer"&gt;and more&lt;/a&gt; to help cover as many use cases as possible. &lt;/p&gt;

&lt;p&gt;Recently, we decided to expand our demo coverage even more with one of our favourite frameworks: &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;In today’s tutorial, we’ll cover how to incorporate &lt;a href="https://www.daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt; into your Vue app, as well as how to programmatically manage Daily Prebuilt controls via your app’s UI with our latest &lt;a href="https://github.com/daily-demos/vue-daily-prebuilt" rel="noopener noreferrer"&gt;demo app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaor4optd83k4ryqu7ni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaor4optd83k4ryqu7ni.png" alt="Vue Daily Prebuilt demo home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in building a custom video chat app with Vue, fear not; we have an upcoming tutorial series on how to do just that. Stay tuned! 👀&lt;/p&gt;




&lt;h2&gt;
  
  
  Tutorial requirements
&lt;/h2&gt;

&lt;p&gt;Before we get started, be sure to &lt;a href="https://dashboard.daily.co/signup" rel="noopener noreferrer"&gt;sign up for a Daily account&lt;/a&gt;. Once you’re logged in, you can either &lt;a href="https://dashboard.daily.co/rooms/create" rel="noopener noreferrer"&gt;create a room&lt;/a&gt; through the Dashboard or through the &lt;a href="https://docs.daily.co/reference#create-room" rel="noopener noreferrer"&gt;REST API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this tutorial, you can clone the &lt;a href="https://github.com/daily-demos/vue-daily-prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt Vue demo repo&lt;/a&gt; and run it locally, or start from scratch and follow along as we build our Vue components.&lt;/p&gt;

&lt;p&gt;To run the Daily Prebuilt Vue demo app locally, clone it and run the following in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view the app, open &lt;code&gt;http://localhost:8080&lt;/code&gt; in the browser of your choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Vue app
&lt;/h2&gt;

&lt;p&gt;If you prefer to create your own Vue app to add Daily Prebuilt to, start by installing the &lt;a href="https://cli.vuejs.org/guide/installation.html" rel="noopener noreferrer"&gt;Vue CLI&lt;/a&gt; globally to your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @vue/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, we can &lt;a href="https://cli.vuejs.org/guide/creating-a-project.html#vue-create" rel="noopener noreferrer"&gt;create a new Vue app&lt;/a&gt; to add Daily Prebuilt to using the Vue CLI.&lt;/p&gt;

&lt;p&gt;In your terminal, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create daily-prebuilt-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the project is created, go to the project’s root directory and add &lt;a href="https://docs.daily.co/reference#using-the-dailyco-front-end-library" rel="noopener noreferrer"&gt;&lt;code&gt;daily-js&lt;/code&gt;&lt;/a&gt; as a dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @daily-co/daily-js 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, following the same instructions as above for the demo app, start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo project overview
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/daily-demos/vue-daily-prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt Vue demo&lt;/a&gt; only has four components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;App.vue&lt;/code&gt;, the parent component for every other component included in the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Header.vue&lt;/code&gt;, a completely optional component we included for the app’s title and project links.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Home.vue&lt;/code&gt;, the main component which is where Daily Prebuilt is embedded and the control panel is added when in a Daily call.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Controls.vue&lt;/code&gt;, the control panel for programmatically controlling Daily Prebuilt. This is also optional but useful for understanding how to interact with &lt;code&gt;daily-js&lt;/code&gt; to customize your app’s usage of Daily Prebuilt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We won’t go into the details of what’s happening in the &lt;code&gt;Header&lt;/code&gt; since it’s static content, but what’s important to know is that the &lt;code&gt;App&lt;/code&gt; component imports the &lt;code&gt;Header&lt;/code&gt; and &lt;code&gt;Home&lt;/code&gt; component, and both are displayed at all times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/Home.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/Header.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ready to go Home: Importing Daily Prebuilt to your Vue app
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Home&lt;/code&gt; component is the most important one in this demo because it loads all the main content, including the Daily call and control panel. &lt;/p&gt;

&lt;p&gt;The default view of the Home component will include two buttons and an input:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first button is only used if you’ve deployed the app via Netlify, so we’ll skip that for now. (Check out the project’s &lt;a href="https://github.com/daily-demos/vue-daily-prebuilt/blob/main/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt; for more information.)&lt;/li&gt;
&lt;li&gt;The input and second button are used to submit the Daily room URL you’ll be joining (i.e. from the Daily room created above). The format of this URL is &lt;code&gt;https://YOUR_DAILY_DOMAIN.daily.co/ROOM_NAME&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The container for this default home view is conditionally rendered depending on the &lt;code&gt;status&lt;/code&gt; value in the component’s data option.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status === 'home'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The status can be &lt;code&gt;home&lt;/code&gt;, &lt;code&gt;lobby&lt;/code&gt;, or &lt;code&gt;call&lt;/code&gt;. &lt;code&gt;home&lt;/code&gt; refers to the default view, before a call has been started, and &lt;code&gt;lobby&lt;/code&gt; refers to when a call has been started but not joined yet. (We call this the “hair check” view sometimes too, so you can view yourself and set up your devices before joining a call.) Lastly, &lt;code&gt;call&lt;/code&gt; refers to when you are live in a Daily call. We’ll look at how the &lt;code&gt;status&lt;/code&gt; value gets updated in a bit. &lt;/p&gt;

&lt;p&gt;There is also a call container &lt;code&gt;div&lt;/code&gt; that is included in the &lt;code&gt;Home&lt;/code&gt; component, which is conditionally displayed depending on the app’s current status. This means it is in the DOM in the default view but only visible to the user once a call has been started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47a6ybb21c3iue9pga6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47a6ybb21c3iue9pga6w.png" alt="The demo join button enables when a valid Daily room URL is entered"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at the Vue template for how this is set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status === 'home'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;Prebuilt&lt;/span&gt; &lt;span class="nx"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Start&lt;/span&gt; &lt;span class="nx"&gt;demo&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;paste&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;own&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start-call-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createAndJoinRoom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;runningLocally&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nx"&gt;Create&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Room&lt;/span&gt; &lt;span class="nx"&gt;could&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subtext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;entered&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
         &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter room URL...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^(https:&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/)?[&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;w.-]+(&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;.(daily&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;.(co)))+[&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/]+[&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;w.-]+$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;validateInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
       &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submitJoinRoom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!validRoomURL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nx"&gt;Join&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{ hidden: status === 'home' }&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;Prebuilt&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;embedded&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt; &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;callRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Only&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt; &lt;span class="nx"&gt;panel&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;live&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;
       &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status === 'call'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;callFrame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we know how the &lt;code&gt;Home&lt;/code&gt; component is structured, let’s look at the JavaScript code that gives it functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DailyIframe&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@daily-co/daily-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Controls&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Controls.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../api.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controls&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;validRoomURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;roomError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;runningLocally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="nf"&gt;created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runningLocally&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;createAndJoinRoom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;api&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="c1"&gt;// Daily callframe created and joined below&lt;/span&gt;
   &lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;

     &lt;span class="c1"&gt;// Daily event callbacks&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goToLobby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lobby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goToCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaveCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;
     &lt;span class="c1"&gt;// DailyIframe container element&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callWrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$refs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="c1"&gt;// Create Daily call&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DailyIframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callWrapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;iframeStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;400px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;920px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid var(--grey)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;showLeaveButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="c1"&gt;// Add event listeners and join call&lt;/span&gt;
     &lt;span class="nx"&gt;callFrame&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;started-camera&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;camera-error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goToLobby&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goToCall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="nf"&gt;submitJoinRoom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="nf"&gt;validateInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validRoomURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkValidity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s start by focusing on the &lt;code&gt;joinRoom&lt;/code&gt; method, which is where all the Daily video call ✨magic✨happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, if there is already a &lt;code&gt;callFrame&lt;/code&gt; (i.e. the video call iframe), we destroy it to avoid multiple calls being loaded unintentionally. Defensive coding FTW. 💅&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Daily event callbacks&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goToLobby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lobby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goToCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaveCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we set up the callbacks that will be used by &lt;code&gt;daily-js&lt;/code&gt; whenever an event happens in the call that will affect our app’s UI. This can be moved outside the &lt;code&gt;joinRoom&lt;/code&gt; function too, but we won’t worry about optimizing for now.&lt;/p&gt;

&lt;p&gt;These callbacks are where we update our data options’ &lt;code&gt;status&lt;/code&gt; value to know what stage of the call we’re in.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const callWrapper = this.$refs.callRef;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we select the &lt;code&gt;div&lt;/code&gt; container that we’ll instruct &lt;code&gt;daily-js&lt;/code&gt; to embed the video call iframe into (the &lt;code&gt;DailyIframe&lt;/code&gt; instance). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;div id="call" ref="callRef"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we look back at the DOM structure, there was a &lt;code&gt;div&lt;/code&gt; included with a ref added to it to simplify selecting that &lt;code&gt;div&lt;/code&gt; in our &lt;code&gt;joinRoom&lt;/code&gt; method. This is what we're targeting with &lt;code&gt;const callWrapper = this.$refs.callRef;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create Daily call&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DailyIframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callWrapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;iframeStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;400px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;920px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid var(--grey)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;showLeaveButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting back to &lt;code&gt;joinRoom&lt;/code&gt;, we then actually create the &lt;code&gt;DailyIframe&lt;/code&gt; that will host our video call and assign it to the variable &lt;code&gt;callFrame&lt;/code&gt;. This variable then gets assigned to our data option so it can be referenced later. (If you were using a state management library, you would add it to your app’s state at this point.)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The options passed to &lt;code&gt;createFrame&lt;/code&gt;, like &lt;code&gt;iframeStyle&lt;/code&gt;, are optional.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add event listeners and join call&lt;/span&gt;
&lt;span class="nx"&gt;callFrame&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;started-camera&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;camera-error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joining-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goToLobby&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joined-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goToCall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left-meeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaveCall&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;callFrame&lt;/code&gt; exists, we can attach all the Daily event listeners to it with our callbacks created earlier, and join the call. To join, make sure you pass the Daily room URL, which is the value the user entered into the input. &lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;join&lt;/code&gt; method is called, you should see two possible views depending on your room’s &lt;code&gt;prejoin UI&lt;/code&gt; settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpmdk5fb50kebgc9gf9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpmdk5fb50kebgc9gf9p.png" alt="Prejoin UI setting in Daily Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have the &lt;code&gt;prejoin UI&lt;/code&gt; option enabled, you will see the lobby view. The &lt;code&gt;joining-meeting&lt;/code&gt; event will get triggered, which will call the &lt;code&gt;goToLobby&lt;/code&gt; callback that we set above. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaouwf8kjihk47kcpdw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaouwf8kjihk47kcpdw9.png" alt="Prejoin UI in Daily Prebuilt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lobby view, you will no longer see the default view because the &lt;code&gt;status&lt;/code&gt; value has changed to &lt;code&gt;lobby&lt;/code&gt;. If we review our DOM elements, we can see the call container now shows because &lt;code&gt;status !== ‘home’&lt;/code&gt; (it equals &lt;code&gt;lobby&lt;/code&gt; now). The controls do not show yet, though, because we’re not officially in the call yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{ hidden: status === 'home' }&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;Prebuilt&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;embedded&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt; &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;callRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Only&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt; &lt;span class="nx"&gt;panel&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;live&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;
       &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status === 'call'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;callFrame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second possible view, if you have the &lt;code&gt;prejoin UI&lt;/code&gt; disabled for the room you’re in, is seeing the call view. This means you are in the Daily call! 💪&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;joined-meeting&lt;/code&gt; event would have been triggered, calling the &lt;code&gt;goToCall&lt;/code&gt; callback we set, which will update the &lt;code&gt;status&lt;/code&gt; to be &lt;code&gt;call&lt;/code&gt;. This status change will cause the controls to now show. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bqib6dduuzdu9me6fks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bqib6dduuzdu9me6fks.png" alt="Daily Prebuilt call UI embedded in Vue app"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Controlling your in-call experience programmatically
&lt;/h2&gt;

&lt;p&gt;One of the best things about Daily Prebuilt is that the hard parts of building video calls are done for you but there are still lots of options that can be configured or customized. &lt;/p&gt;

&lt;p&gt;Once the &lt;code&gt;DailyIframe&lt;/code&gt; instance (our video call iframe) has been created, you have access to dozens of &lt;a href="https://docs.daily.co/reference#instance-methods" rel="noopener noreferrer"&gt;instance methods&lt;/a&gt; to help you manage your call functionality. &lt;/p&gt;

&lt;p&gt;For example, let’s say you want to add a button to your app to leave a call. You can create a button that calls the &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-leave" rel="noopener noreferrer"&gt;&lt;code&gt;.leave()&lt;/code&gt; instance method&lt;/a&gt; on click. &lt;/p&gt;

&lt;p&gt;To look at how some of these methods work, we can review how the &lt;code&gt;Controls&lt;/code&gt; component is set up. &lt;/p&gt;

&lt;p&gt;To start, let’s see which props are passed to the &lt;code&gt;Controls&lt;/code&gt; component where it’s used in &lt;code&gt;Home&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;
   &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status === 'call'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;roomUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;callFrame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;v-if&lt;/code&gt; means the controls are only rendered if the &lt;code&gt;status&lt;/code&gt; value is equal to &lt;code&gt;call&lt;/code&gt;. This means it only shows when a person is live in a call in this demo. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;roomUrl&lt;/code&gt; prop is the URL the user submitted in the default home view. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;callFrame&lt;/code&gt; prop is the DailyIframe instance created for the call, which gives us access to all the instance methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Not all instance methods are available for Daily Prebuilt. Refer to our &lt;a href="https://docs.daily.co/reference#instance-methods" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to know which ones can be used.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s take a look at our &lt;code&gt;Controls&lt;/code&gt; component and see how the HTML is structured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;controls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Call&lt;/span&gt; &lt;span class="nx"&gt;overview&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Invite&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urlInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Share&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;invite&lt;/span&gt; &lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Room&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;share&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urlInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;roomUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;copyUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;teal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;copyButtonText&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Example&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt; &lt;span class="nx"&gt;controls&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;also&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;own&lt;/span&gt; &lt;span class="nx"&gt;meeting&lt;/span&gt; &lt;span class="nx"&gt;controls&lt;/span&gt; &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;daily&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleCamera&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Toggle&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleMic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Toggle&lt;/span&gt; &lt;span class="nx"&gt;mic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleScreenShare&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Toggle&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expandFullscreen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Expand&lt;/span&gt; &lt;span class="nx"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleLocalVideo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;localVideoText&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;video&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleRemoteParticipants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;remoteVideoText&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="nf"&gt;participants &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Speaker&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveCall&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="nx"&gt;Leave&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We display the &lt;code&gt;roomUrl&lt;/code&gt; prop in the input for the user to copy and share with others so they can join the call, too.&lt;/p&gt;

&lt;p&gt;We also have eight buttons included in the control panel to programmatically interact with the &lt;code&gt;DailyIframe&lt;/code&gt; instance. There interactions include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turning the local camera on and off&lt;/li&gt;
&lt;li&gt;Turning the local microphone on an off&lt;/li&gt;
&lt;li&gt;Sharing the local call participant’s screen&lt;/li&gt;
&lt;li&gt;Expanding Daily Prebuilt to be fullscreen&lt;/li&gt;
&lt;li&gt;Hiding and showing the local participant’s tile in the call&lt;/li&gt;
&lt;li&gt;Hiding and showing the participants bar, which is where all the remote participants’ tiles are locally while in speaker mode&lt;/li&gt;
&lt;li&gt;Leaving the call to go back to the default home view&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Toggle your local camera programmatically
&lt;/h3&gt;

&lt;p&gt;To understand how these work, let’s review a couple, starting with toggling the local camera.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;button @click="toggleCamera"&amp;gt;Toggle camera&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To turn the local camera on and off, the control panel button has the following click event attached to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;toggleCamera&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localVideo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;this.callFrame&lt;/code&gt; refers to the &lt;code&gt;callFrame&lt;/code&gt; prop passed in the &lt;code&gt;Home&lt;/code&gt; component, which gives us access to the &lt;code&gt;DailyIframe&lt;/code&gt; instance. We can then call &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-setlocalvideo" rel="noopener noreferrer"&gt;&lt;code&gt;.setLocalVideo()&lt;/code&gt;&lt;/a&gt;, an instance method that accepts a boolean value. &lt;/p&gt;

&lt;p&gt;The current status of the local camera can be accessed with the &lt;code&gt;.localVideo()&lt;/code&gt; instance method, which will return whether the local camera is currently on or off. Since we want this method to toggle the current state, we can pass &lt;code&gt;.setLocalVideo()&lt;/code&gt; whatever the inverse of the current state of the camera is with &lt;code&gt;!this.callFrame.localVideo()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, if the camera is currently on, calling &lt;code&gt;this.callFrame.setLocalVideo(!this.callFrame.localVideo());&lt;/code&gt; is the same as calling &lt;code&gt;this.callFrame.setLocalVideo(false);&lt;/code&gt; to turn it off.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go fullscreen with the click of a button ✨
&lt;/h3&gt;

&lt;p&gt;The other buttons in the control panel mostly work the same way. Let’s take a look at one more example to see how to update your Daily Prebuilt calls programmatically.&lt;/p&gt;

&lt;p&gt;The control panel includes a button to make the Daily Prebuilt iframe fullscreen:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;button @click="expandFullscreen"&amp;gt;Expand fullscreen&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The click handler on this button uses the &lt;code&gt;callFrame&lt;/code&gt; prop to access the &lt;code&gt;DailyIframe&lt;/code&gt; instance, which can then call the &lt;a href="https://docs.daily.co/reference#requestfullscreen" rel="noopener noreferrer"&gt;&lt;code&gt;requestFullscreen()&lt;/code&gt;&lt;/a&gt; instance method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F08%2FCleanShot-2021-08-17-at-13.59.02.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.daily.co%2Fblog%2Fcontent%2Fimages%2F2021%2F08%2FCleanShot-2021-08-17-at-13.59.02.gif" alt="Click fullscreen button to make video call fullscreen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And with one click, you're in fullscreen mode. It’s really as simple as that! 🙌&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Now that you know how to embed &lt;a href="https://www.daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt; in a Vue app, you can add Daily video chat to any Vue projects you’re building! Tag us on Twitter (&lt;a href="https://twitter.com/trydaily" rel="noopener noreferrer"&gt;@trydaily&lt;/a&gt;) to show us your projects. 😊&lt;/p&gt;

&lt;p&gt;In terms of next steps, to learn how to customize your video apps even more, try updating your &lt;a href="https://www.daily.co/blog/introducing-color-theming-for-embeddable-video-calls-a-new-feature-for-daily-prebuilt/" rel="noopener noreferrer"&gt;Daily Prebuilt colour theme&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What redesigning our product taught us about optimizing video call performance in React</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Wed, 21 Jul 2021 20:18:19 +0000</pubDate>
      <link>https://dev.to/trydaily/what-redesigning-our-product-taught-us-about-optimizing-video-call-performance-in-react-4hl1</link>
      <guid>https://dev.to/trydaily/what-redesigning-our-product-taught-us-about-optimizing-video-call-performance-in-react-4hl1</guid>
      <description>&lt;p&gt;&lt;em&gt;Recently, one of Daily’s front-end engineers, Christian Stuff, internally shared several performance improvement tips he discovered while working on Daily Prebuilt. The following discussion is based on that list.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;One of our primary goals at Daily is to help our customers embed reliable and easy-to-use video calls into their apps in the shortest developer time possible. One way we’ve found to do this is by offering &lt;a href="https://www.daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Daily Prebuilt is Daily's ready-to-use, &lt;a href="https://docs.daily.co/docs/embed-the-daily-prebuilt-ui" rel="noopener noreferrer"&gt;embeddable video chat&lt;/a&gt; that can be added to any app with just a few lines of code. This is in comparison to our &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-createcallobject" rel="noopener noreferrer"&gt;call object&lt;/a&gt; option, which enables customers to build their own custom video calls with our core APIs. &lt;/p&gt;

&lt;p&gt;Basically, if Daily Prebuilt is your favourite meal served at a restaurant, Daily's &lt;a href="https://docs.daily.co/docs/build-a-custom-video-chat-interface" rel="noopener noreferrer"&gt;customizable call object&lt;/a&gt; is a bag of groceries and spices with a recipe included. Which one you choose ultimately depends on what your goal is and how many of your own flavours you want to include.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa585g6skqj6ewx8191zk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa585g6skqj6ewx8191zk.jpeg" alt="Daily Prebuilt's UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Redesigning and improving Daily Prebuilt
&lt;/h2&gt;

&lt;p&gt;Recently, we decided to redesign &lt;a href="https://www.daily.co/prebuilt" rel="noopener noreferrer"&gt;Daily Prebuilt&lt;/a&gt; to incorporate some helpful customer feedback we knew would substantially improve Daily Prebuilt’s UX.&lt;/p&gt;

&lt;p&gt;What some customers might not realize is that Daily Prebuilt is actually built with our &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-createcallobject" rel="noopener noreferrer"&gt;call object&lt;/a&gt;. (Yes, we are one of our own customers!) This new, redesigned version also gave us the opportunity to do a deeper dive on the most performant ways to implement Daily’s &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-createcallobject" rel="noopener noreferrer"&gt;call object&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Along the way, we’ve found several solutions to drastically improve Daily Prebuilt’s performance, especially on mobile devices and the problem child of browsers for WebRTC: Safari.&lt;/p&gt;

&lt;p&gt;To help our customers avoid having to learn these lessons on their own, we’ll be covering our most important solutions related to improving performance while using Daily’s call object mode. Many of these are also applicable to WebRTC development in general.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who will find this tutorial helpful?
&lt;/h2&gt;

&lt;p&gt;You’ll find this tutorial useful if you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interested in learning more about browser quirks related to video calls&lt;/li&gt;
&lt;li&gt;A current Daily customer building a custom video chat app&lt;/li&gt;
&lt;li&gt;Shopping around for a video API to help you build a custom video experience&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who will find this tutorial helpful?: Tech stack edition
&lt;/h2&gt;

&lt;p&gt;We’re fond of &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; and &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; at Daily, but these performance tips are mostly front-end framework-agnostic. Regardless of what you’re building your web app with, you can apply these tips to get the most out of your Daily video calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Excuse me, sir: What exactly is the problem?
&lt;/h2&gt;

&lt;p&gt;Before we dive into all the performance optimizations we used to improve Daily Prebuilt, let’s first take a look at how we knew we had a problem. &lt;/p&gt;

&lt;p&gt;One of the main motivators for improving performance has been due to our push to increase call sizes. (1000 participants now, have you heard? 😎) All these additional participants create a new problem: loading participant media. For example, if you’re in a Daily call in speaker mode and scroll through the participant list, videos should load efficiently as they come into view to create a positive user experience. &lt;/p&gt;

&lt;p&gt;Here’s an example of participant bar scrolling in one of the earliest internal versions of the new Daily Prebuilt:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frds0v06a36yzkpybetdc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frds0v06a36yzkpybetdc.gif" alt="Video lagging while scrolling an early version of Daily Prebuilt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We felt the participant bar needed to load the videos faster and more reliably, as a user scrolls through. (Imagine that call with 1000 participants; no one’s got time for that!)&lt;/p&gt;

&lt;p&gt;For comparison’s sake, let’s take a look at the participant bar after we implemented the following performance improvements. It quickly recovers from a scroll much more efficiently. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lmw87ys5axeu5w6yac5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lmw87ys5axeu5w6yac5.gif" alt="Quick video loading on scroll after making performance improvements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another example of slow performance while the new Daily Prebuilt was in development was on mobile. We noticed issues like flickering videos, crackling audio, and delays to user interactions, like button presses. (We might have even heard the word “janky” a couple times during internal testing and cringed.)&lt;/p&gt;

&lt;p&gt;We knew we could do better!&lt;/p&gt;




&lt;h2&gt;
  
  
  Improving performance in video call apps
&lt;/h2&gt;

&lt;p&gt;In this tutorial we'll cover 7 main lessons we learned about improving performance in a custom video chat app. These lessons include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Batching&lt;/strong&gt; &lt;code&gt;daily-js&lt;/code&gt; events, i.e. participant-related events that trigger re-renders&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manually subscribing&lt;/strong&gt; to media tracks in specific use cases&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;virtual scrolling&lt;/strong&gt; in scrollable elements containing videos&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;pagination&lt;/strong&gt; to limit the number of videos shown at a time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memoizing&lt;/strong&gt; elements prone to re-renders&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducing&lt;/strong&gt; how often media elements are added and removed from the DOM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking if a video is paused&lt;/strong&gt; before playing it&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Batching daily-js events
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.daily.co/reference#using-the-dailyco-front-end-library" rel="noopener noreferrer"&gt;daily-js&lt;/a&gt; is an &lt;a href="https://docs.daily.co/reference#events" rel="noopener noreferrer"&gt;events-based&lt;/a&gt; library. Whenever a participant joins a call, updates their device, becomes the active speaker, or anything in between, &lt;code&gt;daily-js&lt;/code&gt; sends an event so you can decide how to update your call UI. (Check out our docs to see a full &lt;a href="https://docs.daily.co/reference#events" rel="noopener noreferrer"&gt;list of Daily events&lt;/a&gt;. 👀)&lt;/p&gt;

&lt;p&gt;For example, you can use the &lt;code&gt;participant-joined&lt;/code&gt; event if you want to listen for when a new participant joins the current call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;participant-joined event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// add another video tile for the new participant &lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The event payload itself will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;participantJoinedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;callFrameId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16257681634230.996506976694651&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;cam_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="na"&gt;joined_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thu Jul 08 2021 14:18:21 GMT-0400 (Eastern Daylight Time)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;screenTrack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;screen_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="na"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d8c55cfb-5eff-4f92-ccee-004989f6b077&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="na"&gt;screenVideo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="na"&gt;screenAudio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d8c55cfb-5eff-4f92-ccee-004989f6b077&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;user_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;will_eject_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wed Dec 31 1969 19:00:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a bunch of people all join a meeting you’re in at the same time, you’ll receive a &lt;code&gt;participant-joined&lt;/code&gt; event for each and every one of them. It can be a lot to handle in calls with dozens (or hundreds!) of people! 😱&lt;/p&gt;

&lt;p&gt;Now let’s say you’re updating a data store for each of these &lt;code&gt;participant-joined&lt;/code&gt; events, such as updating a &lt;code&gt;participants&lt;/code&gt; array in a React store. Updating the state for every &lt;code&gt;participant-joined&lt;/code&gt; event would trigger a re-render for each one, which is not ideal. Instead, you can avoid this by batching &lt;code&gt;participant-joined&lt;/code&gt; events and only update your state every 250ms with all the newly joined participants at once.&lt;/p&gt;

&lt;p&gt;Let’s take a look at how this could look in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleParticipantJoined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinBatchInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Update participants list in React state based on the `joinedSubscriptionQueue` array of new participants&lt;/span&gt;
  &lt;span class="c1"&gt;// Reset queue&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleParticipantJoined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this solution, the &lt;code&gt;participant-joined&lt;/code&gt; event triggers the &lt;code&gt;joinedSubscriptionQueue&lt;/code&gt; to update. Then, an interval is set that waits 250ms for any other new participants to be added to the &lt;code&gt;joinedSubscriptionQueue&lt;/code&gt; before actually triggering any state changes. &lt;/p&gt;

&lt;p&gt;Even with such a small interval of 250ms, batching event-based changes can improve performance, especially in large calls.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind, too, is that when you should actually use event batching will depend on how you are responding to Daily events in your app. Your own implementation will vary based on what is triggering the most avoidable re-renders or UI updates.&lt;/p&gt;

&lt;p&gt;In addition to &lt;code&gt;participant-joined&lt;/code&gt;, batching is useful in other Daily events that are triggered often in calls, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;participant-updated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;participant-left&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;track-started&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;track-stopped&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced Daily events batching: Manual track subscriptions
&lt;/h3&gt;

&lt;p&gt;Let’s take a look at a more advanced example of Daily event batching that uses &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-setsubscribetotracksautomatically" rel="noopener noreferrer"&gt;manual track subscriptions&lt;/a&gt;. This is considered more advanced because Daily manages track subscriptions for you by default; turning on manual track subscriptions will add quite a bit of complexity to your state management and is only recommended in specific use cases. &lt;/p&gt;

&lt;p&gt;If we take the example from above, we can update it for implementing &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-setsubscribetotracksautomatically" rel="noopener noreferrer"&gt;manual track subscriptions&lt;/a&gt; for new participants. Let’s say we want to turn on track subscriptions for every new participant when they join, batching the subscriptions could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleParticipantJoined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinBatchInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;joinedSubscriptionQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subscribed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;subscribed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;setSubscribedTracks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;screenAudio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;screenVideo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateParticipants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;participant-joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleParticipantJoined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above, we create a queue of new participants every 250ms and use the &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-updateparticipants" rel="noopener noreferrer"&gt;&lt;code&gt;updateParticipants&lt;/code&gt;&lt;/a&gt; method to update all the new participants’ subscribed tracks at the same time.&lt;/p&gt;

&lt;p&gt;This version of event batching helps avoid updating each and every new participant individually without creating any noticeable UI delays in displaying participant videos.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Manual track subscriptions: Only subscribe to visible participants
&lt;/h3&gt;

&lt;p&gt;You may be wondering about when to use the example right above, which demonstrates manual track subscription. By default, Daily will handle track subscriptions for you and, for the most part, this is the best solution; let us do the work for you.&lt;/p&gt;

&lt;p&gt;In some situations, however, you may want to take advantage of Daily’s &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-setsubscribetotracksautomatically" rel="noopener noreferrer"&gt;call object option to manually subscribe&lt;/a&gt; to media tracks for participants. This can be useful for improving performance in large calls, as well as certain features like “breakout rooms” where a call is broken into sub-groups. (But, again, most apps do not need to use this feature!)&lt;/p&gt;

&lt;p&gt;In terms of performance, manually subscribing or unsubscribing from tracks is useful in large calls where many videos are not visible. Since the video is not visible, you can unsubscribe from receiving the video tracks from those participants and reduce the amount of data being sent and received related to the call. Only when the participant is moved to being on-screen will you need to re-subscribe to the participant video track.&lt;/p&gt;

&lt;p&gt;Using manual track subscription requires two main Daily methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference#%EF%B8%8F-setsubscribetotracksautomatically" rel="noopener noreferrer"&gt;&lt;code&gt;setSubscribeToTracksAutomatically(false)&lt;/code&gt;&lt;/a&gt;: Be sure to pass &lt;code&gt;false&lt;/code&gt; as a parameter to override the default, which will automatically subscribe to all tracks.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference#%EF%B8%8F-updateparticipant" rel="noopener noreferrer"&gt;&lt;code&gt;updateParticipant()&lt;/code&gt;&lt;/a&gt; or updateParticipants(), which updates several participants at once. To update which the tracks are subscribed to for a participants, pass a &lt;code&gt;setSubscribedTracks&lt;/code&gt; value like so:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateParticipant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, 
  {
    setSubscribedTracks: {
      audio: true,
      video: false,
      screenVideo: false,
    },
  }
);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: If you’re not sure if using manual track subscriptions is a good option for your app, feel free to &lt;a href="https://www.daily.co/contact/support" rel="noopener noreferrer"&gt;ask our team&lt;/a&gt;. We’re happy to help!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Using virtual lists to reduce how many &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements are rendered
&lt;/h3&gt;

&lt;p&gt;One major update with the new Daily Prebuilt design was making the participant bar vertically scrollable. As Daily increases the call size limits, only rendering participant tiles that are actually visible provides a huge performance win. This can be achieved with virtualized lists.&lt;/p&gt;

&lt;p&gt;Virtualized lists (or virtualized scrolling) refers to a list of items where only the visible subset of items is actually rendered in the DOM. As the list is scrolled through, new items (DOM elements) are rendered as they are scrolled into view (or into a “pre-render” area). Conversely, as DOM elements are scrolled out of view, they are destroyed. The goal here is to only render what is visually relevant to the user, and update the list as it is scrolled through.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf0na7wpmh8rgtnqqkqv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf0na7wpmh8rgtnqqkqv.jpeg" alt="Virtualized scrolling"&gt;&lt;/a&gt;&lt;br&gt;
The Daily Prebuilt participant bar is a good candidate for virtualized scrolling because there can be dozens or even hundreds of participants in the participant bar. Depending on the size of your browser window, you may only actually see 5-10 participants at a time. &lt;/p&gt;

&lt;p&gt;To implement virtualized scrolling, there are thankfully several options. If you don’t mind doing some math, you can calculate where you expect the item to be on the screen based on its position in the list, the size of the element, the scroll position, and the height of the container element. If it is visible, you can render it and otherwise not. (Check out this &lt;a href="https://blog.logrocket.com/virtual-scrolling-core-principles-and-basic-implementation-in-react/" rel="noopener noreferrer"&gt;blog post on virtualized lists&lt;/a&gt; that explains this well.)&lt;/p&gt;

&lt;p&gt;To simplify virtualized scrolling even more, you can also use one of the many libraries that will handle the rendering logic for you. React, for example, has several available libraries, like &lt;a href="https://www.npmjs.com/package/react-virtualized" rel="noopener noreferrer"&gt;react-virtualized&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Lastly, if you’re using Daily’s React Native library, &lt;a href="https://github.com/daily-co/react-native-daily-js#readme" rel="noopener noreferrer"&gt;react-native-daily-js&lt;/a&gt;, you can use React Native’s &lt;a href="https://reactnative.dev/docs/flatlist" rel="noopener noreferrer"&gt;&lt;code&gt;FlatList&lt;/code&gt;&lt;/a&gt; or &lt;code&gt;SectionList&lt;/code&gt; components. They are both wrapper components for React Native’s &lt;a href="https://reactnative.dev/docs/virtualizedlist" rel="noopener noreferrer"&gt;Virtualized List&lt;/a&gt; component and will handle all the rendering logic for you, as well. &lt;/p&gt;
&lt;h3&gt;
  
  
  4. Limiting video feeds with pagination
&lt;/h3&gt;

&lt;p&gt;In Daily Prebuilt on desktop, we limit the rendered participant tiles in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Virtualized lists&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In speaker mode, we used virtualized scrolling, as mentioned, to manage the participant bar videos. In grid mode, however, we use pagination to limit how many videos are on the screen at any given time. This allows all participants to be viewable, just not all at the same time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F49tr2iu5tawk71odqzn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F49tr2iu5tawk71odqzn7.png" alt="Daily Prebuilt on desktop with pagination"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The number of videos and the grid’s tile dimensions ultimately depend on the browser window size and what fits best based on our video aspect ratio requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6id3lnftld9ry83acvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6id3lnftld9ry83acvw.png" alt="Daily Prebuilt on mobile with pagination"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Daily Prebuilt’s mobile designs, we’re a lot stricter with our grid layout and never render more than three remote participant tiles at a time. This is because mobile devices (especially iOS devices) use a noticeable amount of CPU resources to decode video. We’ve found mobile devices often can’t handle more than three (or so) videos at a time. Pagination helps manage this CPU bottleneck by allowing users to page through all participants while never rendering more than three remote videos.&lt;/p&gt;

&lt;p&gt;To see an example of how pagination can be implemented with a grid of videos in Daily’s call object, let’s take a look at an example from a React app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;gridRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handlePrevClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Back&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;

      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tiles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tiles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleNextClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Next&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code block above, we render a parent &lt;code&gt;div&lt;/code&gt; element. Inside the &lt;code&gt;div&lt;/code&gt;, there’s a &lt;code&gt;Back&lt;/code&gt; button conditionally rendered if you’re not on the first page. (Alternatively, you could render the button and disable it instead.) Next, we render the participant video tiles. Lastly, there’s another conditional &lt;code&gt;Next&lt;/code&gt; button if you’re not on the last page.&lt;/p&gt;

&lt;p&gt;Now let’s take a look at the tiles being rendered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibleParticipants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;visibleParticipants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Video&lt;/span&gt; &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;visibleParticipants&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we calculate which participants are visible by taking the total number of participants, the page number, and the number of participants per page. With those numbers, we can determine which participants should have tiles rendered for them. &lt;/p&gt;

&lt;p&gt;Once we know the visible tiles, we can render a tile for each one. Each time the page number is increased or decreased by clicking the &lt;code&gt;Next&lt;/code&gt; or &lt;code&gt;Back&lt;/code&gt; buttons, the visible participants can be recalculated and the tile updates.&lt;/p&gt;

&lt;p&gt;By restricting the number of tiles— and, therefore, the number of videos— being rendered at any given time, we can reduce the CPU load of a Daily video call substantially.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Memoizing components that re-render too often
&lt;/h3&gt;

&lt;p&gt;You may have noticed in the example above, we’re using a React hook called &lt;a href="https://reactjs.org/docs/hooks-reference.html#usememo" rel="noopener noreferrer"&gt;&lt;code&gt;useMemo&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const tiles = useMemo(() =&amp;gt; {...}, [dependency1, dependency2]);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; is an example of how to “memoize” React components. Memoization is an effective way to avoid re-computing potentially “expensive” calculations by using the cached computed value until one of the dependencies has changed. (A dependency is a value that affects the rendered output.) Memoization is used here to only update the &lt;code&gt;tiles&lt;/code&gt; value when the dependencies— the values in the second parameter, the array— change. &lt;/p&gt;

&lt;p&gt;Let’s look at another example to see how memoization works. In React, if you have a paragraph element (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;) that displays the sum of two numbers that are each passed as props to a component, you could represent it like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;displayedSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can say pretty confidently that if &lt;code&gt;num1&lt;/code&gt; and &lt;code&gt;num2&lt;/code&gt;’s values don’t change, the &lt;code&gt;displayedSum&lt;/code&gt; element won’t change. (2+2=4, right?) &lt;/p&gt;

&lt;p&gt;By using &lt;code&gt;useMemo&lt;/code&gt;, we’re telling React that it doesn’t need to keep re-rendering this element unless &lt;code&gt;num1&lt;/code&gt; or &lt;code&gt;num2&lt;/code&gt; change, because then it will actually need to calculate the total again.&lt;/p&gt;

&lt;p&gt;In the case of &lt;code&gt;displayedSum&lt;/code&gt;, adding two numbers is probably not a very ”expensive” calculation in terms of CPU usage; however, with a grid of &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements, re-renders can get expensive fairly quickly, especially on mobile devices. &lt;/p&gt;

&lt;p&gt;Preventing expensive re-renders via memoization (or any other methods) is one of the fastest ways to improve performance in your video or audio-only calls. If you’ve noticed any performance issues in your own Daily app, this is a great place to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Avoid unnecessarily removing and adding back videos
&lt;/h3&gt;

&lt;p&gt;This one might sound contrary to what we’ve been saying so far but hear us out.&lt;/p&gt;

&lt;p&gt;While it’s important to remove &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements that aren’t visible, you should avoid unnecessarily adding or tearing down media (video and audio) elements as much as possible. In React, for example, this could mean making sure your React hook dependencies are not too broad and you are not re-rendering media elements when you don’t need to.&lt;/p&gt;

&lt;p&gt;This is especially important on iOS, which will have a noticeable CPU hit when adding and removing media elements unnecessarily. &lt;/p&gt;

&lt;h3&gt;
  
  
  7. Only play paused &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements
&lt;/h3&gt;

&lt;p&gt;You might be starting to notice a pattern here and, well, you’d be right. If we could sum up our suggestions in one (possibly condescending) sentence, it would be, “Don’t do anything you don’t need to do.”&lt;/p&gt;

&lt;p&gt;This is also the case for playing videos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;videoRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaStream&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCanPlay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;

   &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canplay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleCanPlay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canplay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleCanPlay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet from Daily Prebuilt mobile code, we set the &lt;code&gt;srcObject&lt;/code&gt; for the video element (represented by &lt;code&gt;videoRef&lt;/code&gt;) if there’s a video track (&lt;code&gt;videoTrack&lt;/code&gt;) available. Otherwise, the source is set to &lt;code&gt;null&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We then add an event listener for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplay_event" rel="noopener noreferrer"&gt;&lt;code&gt;canplay&lt;/code&gt;&lt;/a&gt; event. The video element is then played as soon as it’s available if it is not already playing. For example, the video may get paused when disconnecting a Bluetooth audio device, so adding this event listener will help ensure the video is resumed as soon as its media stream is ready again.&lt;/p&gt;

&lt;p&gt;You might be wondering if it really matters if you call &lt;code&gt;play()&lt;/code&gt; on a video that’s not paused. It turns out checking if a video is actually paused before playing it does help performance, especially on iOS Safari.&lt;/p&gt;

&lt;p&gt;As we discovered rewriting Daily Prebuilt for mobile, playing a video that is already playing on iOS Safari is not a "no-op". The action of playing a video, even if it is already playing, takes about 300ms to complete.&lt;/p&gt;

&lt;p&gt;This means adding a simple check to see if the video is paused before playing will actually reduce the CPU usage of your Daily call on mobile.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If there’s one thing we appreciate about WebRTC video calls at Daily, it’s that getting performance right across browsers and devices is tough. Hopefully, these lessons we’ve learned along the way help you customize your Daily calls even faster. &lt;/p&gt;

&lt;p&gt;To learn more about building a custom Daily video call, check out our &lt;a href="https://github.com/daily-demos/call-object-react" rel="noopener noreferrer"&gt;React demo repo&lt;/a&gt;, as well as our &lt;a href="https://www.daily.co/blog/building-a-custom-video-chat-app-with-react/" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; that goes along with it.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webrtc</category>
      <category>javascript</category>
      <category>video</category>
    </item>
    <item>
      <title>A New Kind of PR: Finding Running as a Remote Software Developer</title>
      <dc:creator>Jess Mitchell</dc:creator>
      <pubDate>Mon, 26 Oct 2020 14:16:45 +0000</pubDate>
      <link>https://dev.to/gemontracks/a-new-kind-of-pr-finding-running-as-a-remote-software-developer-3dih</link>
      <guid>https://dev.to/gemontracks/a-new-kind-of-pr-finding-running-as-a-remote-software-developer-3dih</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ojroZcd3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xhrxwifiug6dac9u625n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ojroZcd3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xhrxwifiug6dac9u625n.jpg" alt="Waterfront Trail by my house"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This week I had a new PR. Not my regular kind of PR that you'd see in my Github stats, but the kind I've been having before I start work in the mornings: a Personal Record. I hit 500 kilometers since I started tracking my runs back in April. I also hit a new longest distance with 15km yesterday. &lt;/p&gt;

&lt;p&gt;Running, it turns out, has become the trick I've been looking for to stay healthy as a remote employee. I've been working remotely since 2017 and, for the most part, I've loved it. Despite being much more productive working from home, I've never totally felt like I've figured out the balance of being remote. Any socializing I used to get from being in an office I now had to make time for in my schedule. Any physical activity I got from going to work I'd also have to find time for. Scheduling became much more intentional too; flex schedules are great but can lead to long work days if you don't stay focused. &lt;a href="https://blog.jessmitchell.ca/reframing-anxiety"&gt;Managing my anxiety&lt;/a&gt; also became a bigger challenge while spending so much time at home.&lt;/p&gt;

&lt;p&gt;Finding this balance is likely what a lot of people have been thrown into unexpectedly this year: you need to get your work done, while also getting in some daily movement, while also having time to rest, while also not being crushed by the weight of 2020. (Shout out to parents who have way more on their plate than I do-- I genuinely don't know how you do it all.)&lt;/p&gt;

&lt;p&gt;Previous to going remote, I just walked everywhere. It was the perfect solution for me because it gave me time to de-stress after work, to get in some movement, and to listen to audiobooks or podcasts (i.e. mental stimulation too). It also gave me the space to think and to solve coding problems I was stumped on at work. Walking pretty much helped every aspect of my day. &lt;/p&gt;

&lt;p&gt;Then I went remote and didn't really need to walk further than a few meters from my bedroom to my desk. I tried going to a gym but it took up too much time and felt too body-focused. I also tried doing yoga every morning, which I still do pretty regularly, but I was definitely spending too much time inside already.&lt;/p&gt;

&lt;p&gt;What I needed was an activity to burn off a lot of (mental and physical) energy, that I could do outside, didn't take up too much time, something that you can do through the winter, and had some sense of community to it. &lt;/p&gt;

&lt;p&gt;Enter running. 🏃‍♀️&lt;/p&gt;

&lt;p&gt;Last January I decided to try out the Couch to 5k app. I was a little skeptical because the last time I tried to get into running 4-5 years ago I got migraines after almost every run. And 5 or so years before that I had done some running but it was back when I was using exercise to manage my weight. Honestly, I hated every minute of it back then because it always felt like punishment.&lt;/p&gt;

&lt;p&gt;This time I'd have to approach it from a more balanced perspective. Knowing that I'm sensitive to migraines, I had to figure out why running had been triggering them for me in the past. (Turns out I was going to hard, too fast, with terrible pre- and post- hydration routines.) I also knew I had to approach running from an anti-diet perspective: it shouldn't ever be in response to what I've eaten or to try to control my weight. It should literally just be to get out and run. To move, to get the mood boost, to challenge myself, and to have some space to think.&lt;/p&gt;

&lt;p&gt;I decided to go slow and just follow the app's schedule. (I'm someone who likes to dive into things so going slow can feel pretty frustrating.) By March I ran my first 5k without stopping and I felt great about it. It got me out of the house, only took about 30 minutes, and gave me the chance to discover new parts of my neighbourhood. I noticed how much it was improving my mood and I made sure to never go if I &lt;em&gt;really&lt;/em&gt; didn't want to to make sure it didn't become another thing I &lt;em&gt;had&lt;/em&gt; to do.&lt;/p&gt;

&lt;p&gt;(Sidenote: Hopefully this goes without saying, but whenever I run it's on a super quiet trail by my house with a mask in case I have to pass anyone.)&lt;/p&gt;

&lt;p&gt;After completing the app, I had to decide what was next. A 10k? A half-marathon? Immediately I went from 1 to 100 in my head to see how far I could push myself. And then I stopped. This wasn't supposed to be something that was &lt;em&gt;super&lt;/em&gt; challenging that I would eventually start to resent. It was meant to be a regular practice to help me feel mentally and physically balanced.&lt;/p&gt;

&lt;p&gt;And so the practice began.&lt;/p&gt;

&lt;p&gt;Instead, I decided to stick with 5k. It's not a big time commitment, it's long enough to be a real work out, and it could be as relaxed or challenging as I made it.&lt;/p&gt;

&lt;p&gt;I decided to give myself a monthly total distance goal to stay motivated and increased it just a bit each month. 50k, 60k... by August I had finished 100k total in one month (or 20 5k runs). After running 100k total I decided not to increase anymore. Running 5 days a week was more than I was looking for long term, so I'd need a new goal. &lt;/p&gt;

&lt;p&gt;After running 5k so many times and noticing that my legs were feeling a &lt;em&gt;lot&lt;/em&gt; stronger, I decided it would be fun to see if I could do a 10k. There was a virtual race here in Hamilton (the Run for Women fundraiser) at the end of September, so the timing was perfect and it'd be an opportunity to raise some money as well.&lt;/p&gt;

&lt;p&gt;Throughout September, I kept a few 5k runs during the week and used my Saturday runs to build up the longer distance. 6k, 7k, 8, 9k, and eventually 10k five Saturdays in a row. It felt incredible.&lt;/p&gt;

&lt;p&gt;Since running my first 10k I've relaxed my weekday running schedule a bit to increase my Saturday long run distances. Yesterday I ran 15k. My pace was slow, I'm pretty sure I don't know how to breathe properly, and I avoided every hill I could. But I did it! And it felt great.&lt;/p&gt;

&lt;p&gt;More than anything, running has represented one of my most important lessons-- one that I seem to need to learn over and over again and one that has made me a better programmer, as well: it's what we do a little over a long time (what we practice) that leads to real progress.&lt;/p&gt;

&lt;p&gt;Now back to my regular PRs. 💻&lt;/p&gt;

</description>
      <category>running</category>
      <category>remote</category>
      <category>remotework</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
