DEV Community

Cover image for How to build a Twitch chat overlay with HTML, CSS and JS
Anneta Wamono
Anneta Wamono

Posted on • Updated on

How to build a Twitch chat overlay with HTML, CSS and JS

Like me, you may have started watching more Twitch streams in the last two years. One of the things that makes a Twitch stream fun and interactive are the overlays that react to the chat's input. So by the end of this tutorial, you'll have a simple chat overlay to use in your streams. You can take this tutorial and build on it to make more complex and interactive overlays.

Prerequisites

If you are a beginner at web dev, this is for you. To complete this tutorial, you'll need to know some HTML, CSS, JS. We'll need ComfyJS to complete the project.

Project requirements:

Table of contents

  1. Setting up the project
  2. Connecting to Twitch chat
  3. Sending messages to the DOM
  4. Styling
  5. Adding animation
  6. Adding different styles based on roles

Setting up the project

We'll be writing our code in a single HTML file. Create a chat.html file and add the following:



<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Twitch chat</title>
</head>
<body>
    <div id="chat">
        <ul>
        </ul>
    </div>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

We'll be putting our Twitch messages in the <ul> block as <li> elements. Next, let's integrate with Twitch.

Connecting to our Twitch chat

We'll be using ComfyJS to integrate with our Twitch chat. It's a very easy-to-use library, and it only takes a few lines of code to connect with our chat. Let's add this code to our <head>:



<script src="https://cdn.jsdelivr.net/npm/comfy.js@latest/dist/comfy.min.js"></script>


Enter fullscreen mode Exit fullscreen mode

Next, we need to add a <script> tag below our <body> tag and add the following:



ComfyJS.onChat = (user, message, flags, self, extra) => {
        console.log(user, message);
}

ComfyJS.Init("YourTwitchName");


Enter fullscreen mode Exit fullscreen mode

ComfyJS.Init() lets us connect to our Twitch account, so remember to replace YourTwitchName with your channel name. We want to test if we're connected to our chat, and we can do that by going to our Twitch Creator Dashboard and selecting Stream Manager. There, you'll see a "My Chat" window where you can send messages to test your code. If you open chat.html in your browser and open your dev tools, you'll see the messages appear.

Sending Hello There to Twitch chat and it appears in the console

Sending messages to the DOM

So now that we're receiving messages from our chat let's start sending them to our DOM. We'll adjust our code in our <script> to the following:



var chat = document.querySelector("#chat>ul");

ComfyJS.onChat = (user, message, flags, self, extra) => {
        var newMessage = document.createElement("li");
        newMessage.innerText = `${user}: ${message}`;
        chat.append(newMessage);
}

ComfyJS.Init("YourTwitchName");


Enter fullscreen mode Exit fullscreen mode

We're creating a new <li> element for each message we receive and adding the user and message to it. That gets appended to our <ul> block.

Sending message Now I'm in a an li element in chat and it appears in the DOM

We want to separate the user from the message and give it some spacing for our purposes. So we'll change the code to the following:



var chat = document.querySelector("#chat>ul");

ComfyJS.onChat = (user, message, flags, self, extra) => {
        var newMessage = document.createElement("li");
        var text = document.createElement("blockquote");

        newMessage.innerText = user;
        text.innerText = message;

        newMessage.append(text);
        chat.append(newMessage);
}


Enter fullscreen mode Exit fullscreen mode

Styling

Our chat is working, but we don't want to add it to our stream in this state๐Ÿ˜…. Let's add some CSS to make it look more impressive. Start by adding <style> tags to our <head>. To that, we're going to add these rules:

Fix the width and height of our chat



#chat {
    width: 400px;
    height: 350px;
}


Enter fullscreen mode Exit fullscreen mode

You can set this to any width and height. Just remember what values you've chosen for later.

Style the messages



#chat li {
    background-color: hsl(196, 58%, 93%);
    box-sizing: border-box;
    padding: 1rem 10px;
    margin-bottom: 10px;
}

#chat ul {
    list-style-type: none;
    list-style-position: outside;
}


Enter fullscreen mode Exit fullscreen mode

Note: We're using box-sizing: border-box; here so that our padding and margins don't increase the width of our messages.

Set chat to auto overflow



#chat {
    width: 400px;
    height: 350px;
    overflow-y: auto; 
}


Enter fullscreen mode Exit fullscreen mode

We're setting the overflow-y property because we want to affect the vertical overflow of the chat. We set it to auto because we want the chat to start its scrolling behaviour when it starts to overflow.

Display the chat from the bottom up



#chat {
    width: 400px;
    height: 350px;
    overflow-y: auto; 
    display: flex;
    flex-direction: column-reverse;
}


Enter fullscreen mode Exit fullscreen mode

We want the last message to appear in our chat and push our older messages up and off the screen. To do this we set our display property to flex and set the flex-direction to column-reverse.

Remove scrollbars



#chat::-webkit-scrollbar {
    display: none;
}


Enter fullscreen mode Exit fullscreen mode

At this point, our chat is starting to look decent. Below is the full stylesheet with additional rules to get our final result:



html,body {
    margin: 0;
    font-family: monospace;
    color: hsl(197, 62%, 32%);
}

#chat {
    width: 400px;
    height: 350px;
    overflow-y: auto;
    display: flex;
    flex-direction: column-reverse;
}

#chat::-webkit-scrollbar {
    display: none;
}

#chat ul {
    list-style-type: none;
    list-style-position: outside;
}

#chat li {
    background-color: hsl(196, 58%, 93%);
    box-sizing: border-box;
    padding: 1rem 10px;
    margin-bottom: 10px;
    border: 4px solid;
}

#chat blockquote {
    font-size: 1.2rem;
}


Enter fullscreen mode Exit fullscreen mode

Sending message Very stylish on chat and it appears as a styled message in the browser

Adding animation

To make our chat look even cooler, we're going to have each new message enter and slide in from the left. First, we want to define our @keyframes animation:



@keyframes slide-in-left {
    from {
        transform: translateX(400px);
        opacity: 0;
    }

    to {
        transform: translateX(0);
        opacity: 1;
    }
}


Enter fullscreen mode Exit fullscreen mode

Next, we'll target our most recent message with last-of-type and apply the animation to it:



#chat li:last-of-type {
    animation-name: slide-in-left;
    animation-duration: 0.15s;
    animation-timing-function: ease-in;
}


Enter fullscreen mode Exit fullscreen mode

These 2 CSS rules are enough to give us an entrance animation. You can try and make the top message animate off screen using li:nth-child() as a bonus activity.

Finally, to make the newest message stand out, we'll make our older messages a bit transparent:



#chat li:not(:last-of-type) {
    opacity: 0.5;
}


Enter fullscreen mode Exit fullscreen mode

Sending message Animation on chat and the message animates in on the browser
Here is the final result with the animation.

Conclusion

We've made a great looking chat overlay, and now you can show your audience what you've made on your streams. Here is a tutorial on how you can add your HTML file to OBS. It will run just like it did in our browser, but remember to set the width and the height to the same values we used for #chat in our CSS. And here is a repo of this project on Github.

This was just a taste of what you can do with ComfyJS. It's a great library for making fun projects for your stream. Check out PixelPlush, TrostCodes, and whitep4nth3r for inspiration on overlay and interaction ideas. Thank you to LunchDevCommunity for their rudimentary chat overlay.

Lastly, I challenge you to extend this chat by setting different colours for your mods and subscribers (hint: you can use the flags mod and subscriber).


Thank you for reading my article. I'm new to writing, so any feedback on whether this was helpful or not, or topics you might be interested in are welcome.

See you at the next one!

Top comments (5)

Collapse
 
vastikrisz profile image
Krisztiรกn Vastag

Amazing article, it really helped out a lot. I'm really new in the frontend business (only a student) so I don't really have a deep understanding of JS yet. Could I perhaps ask you to tell me how I could display badges and emotes as well?

Collapse
 
annetawamono profile image
Anneta Wamono

Hi Krisztiรกn,

Thank you for your feedback! Right now, with ComfyJS (which is the library used to connect with the Twitch chat) you aren't able to get the actual images for badges and emotes. There is a an extra parameter that contains information like the emote id, but I haven't tried using it to reference an emote image. If someone else knows more, hopefully they can let us know.

Collapse
 
casinoira profile image
Casinoira • Edited

I just tried developing a twitch chat overlay and figured out how to parse the emote and badge through its id.

With emote it is easier as you can just use this function I found from a tmi development thread here

For badge, get this JSON file. There may be a cleaner simpler solution, but I just loop through the extra.userBadges parameter and compare and grab the image from the JSON file above. A rather brute force way.

I hope I explain it well enough, I'm not really good with the technical web development term haha

Thread Thread
 
annetawamono profile image
Anneta Wamono

These resources are great! Thanks for sharing.

Thread Thread
 
casinoira profile image
Casinoira

No problem, it's quite difficult to come by documentation or solution for comfy.js. Is only by chance I found out that it used tmi library for twitch that I was able to find out how to parse emotes and badges as image. Hopefully this is another tip for some other features that future developers want to develop, try to look into tmi development too.