The Tuts+ YouTube channel is quick approaching 1.5M subscribers. Let’s have fun this nice achievement by creating one thing YouTube-oriented! We’re going to construct a easy, but totally practical YouTube app with Vanilla JavaScript.
The idea will likely be fairly simple; we’ll construct a easy UI the place we are able to enter the ID of a channel and our app will return information about it.
1. Scaffolding the YouTube App
Earlier than we begin creating our app, there are some things that we’ve got to handle.
Seize a YouTube API key
As a primary and obligatory factor, we must always get a YouTube API key that may give us entry to the YouTube Information API. To take action, we must always observe the directions on this page and arrange a venture within the Google Cloud Console with the YouTube Information API v3 enabled. In my case, I’ve already achieved it whereas constructing the app. Now, it’s your flip to generate an API and embrace it in your forked demo.



For manufacturing environments, keep in mind that it’s all the time smart to limit the API requests to particular web sites, IP addresses, and many others.
Seize a Lottie Animation
Optionally, to make our app as distinctive as potential, we’ll seize a Lottie animation from the LottieFiles library and play it for channels with 1M or extra subscribers.



First, we’ll generate an asset hyperlink for this animation and customise it as we want.



As issues transfer shortly, at this level, the LottieFiles group suggests utilizing the dotLottie file format as a substitute of the normal Lottie JSON to scale back the file measurement.



In our case, as we’re utilizing a CodePen demo, we’ll import the required .mjs
file like this:
1 |
import { DotLottiePlayer } from "https://webdesign.tutsplus.com/https://unpkg.com/@dotlottie/player-component@newest/dist/dotlottie-player.mjs"https://webdesign.tutsplus.com/; |
Then, as we’ll see in an upcoming part, we’ll embrace the generated dotlottie-player
part within the markup that represents the channel information.
In addition to, when you want a refresher about methods to embrace Adobe After Results animations on an online web page and Lottie Animations basically, think about the next tutorials:
2. Outline the Web page Markup
Let’s now give attention to the app growth.
We’ll solely outline a piece that may embrace a heading, a search kind, and an empty span
ingredient.
We’ll set the enter
ingredient as required and power it to attend 24 characters to keep away from pointless AJAX requests. From my assessments, I’ve seen that the size of a YouTube channel ID is 24, though you’ll be able to replace the minlength
and maxlength
attribute values when you discover one thing totally different.
The span
ingredient will seem with an applicable message underneath sure situations. For instance, if we seek for a YouTube channel ID that doesn’t exist or if, for some motive, the response is unsuccessful (i.e. 400 Dangerous Request, 404 Not Discovered, and many others.).
Alongside the best way, we’ll see the markup for the channel information that will likely be generated dynamically.
Right here’s the preliminary web page markup:
1 |
|
2 |
|
3 |
|
4 |
Easy App With the YouTube API |
5 |
|
6 |
|
7 |
|
8 |
kind="search" minlength="24" maxlength="24" placeholder="Insert a sound YT channel ID" autofocus required>
|
9 |
|
10 |
class="msg"https://webdesign.tutsplus.com/>
|
11 |
|
12 |
|
13 |
|
Discover a YouTube Channel ID
One fast method to discover the ID of a YouTube channel is thru the web page supply. First, navigate to the specified channel web page, then view its supply code and seek for https://www.youtube.com/channel/
. The channel ID will come after this base URL.






3. Set the Foremost Kinds
As it is a giant tutorial, for the sake of simplicity, we’ll skip the beginning kinds and solely consider the principle ones—you’ll be able to view all of them by clicking the CSS tab of the demo.
Kind Kinds
On medium screens and above (>700px), the structure ought to appear like this:



On smaller screens, the shape parts will cut up into two strains:



Listed below are the related kinds:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.top-banner kind { |
4 |
place: relative; |
5 |
show: grid; |
6 |
grid-template-columns: 1fr auto; |
7 |
grid-gap: 15px; |
8 |
align-items: middle; |
9 |
justify-content: middle; |
10 |
max-width: 1000px; |
11 |
}
|
12 |
|
13 |
.top-banner kind enter { |
14 |
font-size: clamp(24px, 2vw, 32px); |
15 |
peak: 40px; |
16 |
padding-bottom: 10px; |
17 |
border-bottom: 1px stable currentColor; |
18 |
}
|
19 |
|
20 |
.top-banner kind enter::placeholder { |
21 |
opacity: 1; |
22 |
coloration: var(--white); |
23 |
}
|
24 |
|
25 |
.top-banner kind button { |
26 |
font-weight: daring; |
27 |
padding: 15px 30px; |
28 |
border-radius: 5px; |
29 |
background: var(--red); |
30 |
transition: background 0.3s ease-in-out; |
31 |
}
|
32 |
|
33 |
.top-banner kind button:hover { |
34 |
background: var(--darkred); |
35 |
}
|
36 |
|
37 |
.top-banner kind .msg { |
38 |
place: absolute; |
39 |
prime: 100%; |
40 |
left: 0; |
41 |
}
|
42 |
|
43 |
@media (max-width: 700px) { |
44 |
.top-banner kind { |
45 |
grid-template-columns: 1fr; |
46 |
}
|
47 |
|
48 |
.top-banner kind .msg { |
49 |
place: static; |
50 |
}
|
51 |
}
|
Channel Kinds
As quickly as we efficiently get again from the server information for a channel, they may seem in a card structure like this:



The kinds aren’t something too sophisticated, so we received’t go into extra element at this level:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.card { |
4 |
padding: 4%; |
5 |
text-align: middle; |
6 |
margin-top: 70px; |
7 |
coloration: var(--white); |
8 |
background: var(--total-black); |
9 |
border-radius: 7px; |
10 |
overflow: hidden; |
11 |
}
|
12 |
|
13 |
.card .particulars img { |
14 |
border-radius: 50%; |
15 |
}
|
16 |
|
17 |
.card .particulars .title { |
18 |
margin-top: 10px; |
19 |
}
|
20 |
|
21 |
.card .particulars .description { |
22 |
max-width: 80%; |
23 |
margin: 30px auto 0; |
24 |
}
|
25 |
|
26 |
.card .total-videos { |
27 |
place: relative; |
28 |
z-index: 1; |
29 |
margin-top: 30px; |
30 |
}
|
31 |
|
32 |
.card .total-subscribers { |
33 |
place: relative; |
34 |
show: inline-grid; |
35 |
grid-template-columns: auto auto; |
36 |
grid-gap: 10px; |
37 |
align-items: middle; |
38 |
font-weight: daring; |
39 |
margin-top: 60px; |
40 |
background: var(--red); |
41 |
}
|
42 |
|
43 |
.card .total-subscribers dotlottie-player { |
44 |
place: absolute; |
45 |
prime: 50%; |
46 |
left: 50%; |
47 |
remodel: translate(-50%, -50%); |
48 |
}
|
49 |
|
50 |
.card .total-subscribers .outer { |
51 |
padding: 10px; |
52 |
}
|
53 |
|
54 |
.card .total-subscribers svg { |
55 |
fill: var(--red); |
56 |
background: var(--white); |
57 |
padding: 5px; |
58 |
box-sizing: content-box; |
59 |
}
|
4. Add the JavaScript
At this second, we’re able to construct the core performance of our YouTube app. Let’s do it!
On Kind Submission
Every time a consumer submits the shape by urgent the Enter key or the Submit button, we’ll do two issues:
- Cease the shape from submitting, therefore forestall reloading the web page.
- Seize the worth that’s contained within the search subject.
Right here’s the beginning code:
1 |
const topBanner = doc.querySelector("https://webdesign.tutsplus.com/.top-banner"https://webdesign.tutsplus.com/); |
2 |
const kind = topBanner.querySelector("https://webdesign.tutsplus.com/kind"https://webdesign.tutsplus.com/); |
3 |
const enter = topBanner.querySelector("https://webdesign.tutsplus.com/enter"https://webdesign.tutsplus.com/); |
4 |
|
5 |
kind.addEventListener("https://webdesign.tutsplus.com/submit"https://webdesign.tutsplus.com/, (e) => { |
6 |
e.preventDefault(); |
7 |
const channelId = enter.worth; |
8 |
});
|
Carry out an AJAX Request
Earlier than we undergo the AJAX request, it’s essential to learn the docs and perceive methods to construction it. In our case, we need to get channel information, so we’ll give attention to the channel endpoint and move the next parameters:
- The
half
parameter with values thesnippet
andstatistics
names. - The API key. Once more, it’s best to use your personal key.
- The channel ID we’re to get information. In a earlier part, we coated a method to discover the ID of an present channel.
We will even experiment with the HTTP requests via the helper device that’s obtainable on the best aspect of this page.



With all of the above in thoughts, our request URL ought to look one thing like this:
1 |
const BASE_URL ="https://webdesign.tutsplus.com/https://www.googleapis.com/youtube/v3/channels?half=statistics,snippet"https://webdesign.tutsplus.com/; |
2 |
const API_KEY = "https://webdesign.tutsplus.com/AIzaSyAHupLf37J-vEziyQ-pItfoaLS5XUqdVq8"https://webdesign.tutsplus.com/; |
3 |
const channelID = enter.worth; |
4 |
|
5 |
const url = `${BASE_URL}&id=${channelId}&key=${API_KEY}`; |
We’ll use the Fetch API to carry out the AJAX request—I assume you’re conversant in this system. There’s additionally a series when you want a refresher. As mentioned beforehand, we’ll add correct error dealing with for unsuccessful instances. For instance, if we seek for a non-existing channel or the standing request hasn’t succeeded.



So, our AJAX request would look one thing like this:
1 |
...
|
2 |
|
3 |
kind.addEventListener("https://webdesign.tutsplus.com/submit"https://webdesign.tutsplus.com/, (e) => { |
4 |
...
|
5 |
|
6 |
fetchYTStatistics(channelId) |
7 |
.then((knowledge) => { |
8 |
if (typeof knowledge.gadgets !== "https://webdesign.tutsplus.com/undefined"https://webdesign.tutsplus.com/) { |
9 |
createCard(knowledge); |
10 |
} else { |
11 |
msg.textContent = "https://webdesign.tutsplus.com/Please seek for a sound YT channel ID 😩"https://webdesign.tutsplus.com/; |
12 |
}
|
13 |
})
|
14 |
.catch((error) => { |
15 |
msg.textContent = error; |
16 |
});
|
17 |
});
|
18 |
|
19 |
async perform fetchYTStatistics(channelId) { |
20 |
const url = `${BASE_URL}&id=${channelId}&key=${API_KEY}`; |
21 |
const response = await fetch(url); |
22 |
|
23 |
if (!response.okay) { |
24 |
return Promise.reject( |
25 |
`One thing is not working as anticipated. Error: ${response.standing}` |
26 |
);
|
27 |
}
|
28 |
const knowledge = await response.json(); |
29 |
return knowledge; |
30 |
}
|
Right here’s an instance of the response knowledge:



Construct the Card
With the AJAX request in place, every time we kind a channel ID within the search subject, the API will return channel knowledge if they’re obtainable. We’ll then gather solely the required knowledge and fasten it to the web page as a card part.
Two issues to notice right here:
- The Lottie animation will play provided that the channel subscribers are not less than 1M.
- We’ll use the NumberFormat API to format the numbers associated to the channel movies and subscribers.
- The exterior hyperlinks received’t work until you view the CodePen demo in debug mode.
Right here’s the code accountable for this job:
1 |
perform createCard(knowledge) { |
2 |
const allData = knowledge.gadgets[0]; |
3 |
const { customUrl, title, description, thumbnails } = allData.snippet; |
4 |
const { default: thumbnail } = thumbnails; |
5 |
const { videoCount, subscriberCount } = allData.statistics; |
6 |
const div = doc.createElement("https://webdesign.tutsplus.com/div"https://webdesign.tutsplus.com/); |
7 |
div.classList.add("https://webdesign.tutsplus.com/card"https://webdesign.tutsplus.com/, "https://webdesign.tutsplus.com/container"https://webdesign.tutsplus.com/); |
8 |
|
9 |
const markup = ` |
10 |
|
11 |
|
12 |
|
13 |
${customUrl}" goal="_blank">${title} |
14 |
|
15 |
${description} |
16 |
|
17 |
|
18 |
${customUrl}/movies" goal="_blank">Browse |
19 |
${formatNumber(videoCount)} movies
|
20 |
|
21 |
|
22 |
${ |
23 |
subscriberCount >= 1000000 |
24 |
? ` |
25 |
: "" |
26 |
} |
27 |
|
28 |
${formatNumber(subscriberCount)}
|
29 |
Subscribers
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
`; |
36 |
|
37 |
div.innerHTML = markup; |
38 |
doc.physique.appendChild(div); |
39 |
}
|
40 |
|
41 |
perform formatNumber(quantity) { |
42 |
return new Intl.NumberFormat("https://webdesign.tutsplus.com/en"https://webdesign.tutsplus.com/, { |
43 |
notation: "https://webdesign.tutsplus.com/compact" |
44 |
}).format(quantity); |
45 |
}
|
The generated markup because it’s rendered within the browser console:



Reset Issues
Lastly, after the AJAX request, we’ll do the next:
- Take away the
.card
ingredient from the web page. -
Clear the content material of the
.msg
ingredient. - Clear the worth of the search subject and provides focus to that subject.
Right here’s the associated code:
1 |
...
|
2 |
|
3 |
if (doc.querySelector("https://webdesign.tutsplus.com/.card"https://webdesign.tutsplus.com/)) { |
4 |
doc.querySelector("https://webdesign.tutsplus.com/.card"https://webdesign.tutsplus.com/).take away(); |
5 |
}
|
6 |
msg.textContent = ""https://webdesign.tutsplus.com/; |
7 |
kind.reset(); |
8 |
enter.focus(); |
Your YouTube App Is Prepared!
Finished, of us! This actually was fairly an extended journey, so thanks for following alongside! I hope you loved the tip end result and that helped you study some new issues.
As soon as once more, don’t overlook to place your personal key for stay app testing!
As a reminder, let’s look once more on the app:
As all the time, thanks loads for studying!
Subsequent Steps
There are such a lot of issues that you are able to do to increase the performance of this YouTube app. Listed below are some ideas:
- Create one other part to point out the most recent channel movies.
- As a substitute of exhibiting only a channel every time, modify the code to point out a number of channel information concurrently in a grid format, as we did with the climate app.
If there’s anything that you just may need to see as an app extension, tell us on X or within the demo comments!
Uncover Extra JavaScript Tutorials and Sources
Considering training trendy JavaScript via enjoyable hands-on initiatives? In that case, take a look at these JavaScript tutorials: