Frontend HTML — Login Screen & Chat Layout
HTML describes structure — what appears on screen. We build two screens in one page: a login form and a chat area. The chat screen stays hidden until the user joins a room (JavaScript toggles visibility in Lesson 6).
Create public/index.html and paste the full file below.
Full index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Node.js Chat App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- LOGIN SCREEN — shown first -->
<div id="login-screen" class="screen">
<div class="login-card">
<h1>💬 Chat App</h1>
<p class="subtitle">Join a room and start chatting in real time</p>
<label for="username">Your name</label>
<input type="text" id="username" placeholder="e.g. Alex" maxlength="20" autocomplete="off" />
<label for="room">Room name</label>
<input type="text" id="room" placeholder="e.g. general" maxlength="30" autocomplete="off" />
<button id="join-btn" type="button">Join Chat</button>
<p id="login-error" class="error hidden"></p>
</div>
</div>
<!-- CHAT SCREEN — hidden until user joins -->
<div id="chat-screen" class="screen hidden">
<header class="chat-header">
<div>
<h2 id="room-title">Room</h2>
<p id="typing-indicator" class="typing hidden"></p>
</div>
<aside id="online-users" class="online-users" aria-label="Online users"></aside>
</header>
<main id="messages" class="messages" aria-live="polite"></main>
<footer class="chat-input-bar">
<input type="text" id="message-input" placeholder="Type a message…" autocomplete="off" />
<button id="send-btn" type="button">Send</button>
</footer>
</div>
<!-- Socket.IO client library (served automatically by our server) -->
<script src="/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</body>
</html>
Section-by-section explanation
<head> — page metadata
viewportmeta tag — makes layout work on mobile phonesstyle.css— linked stylesheet (Lesson 5)
Login screen (#login-screen)
Contains:
#username— text input for display name#room— text input for room name (e.g.general)#join-btn— button that triggers join logic inclient.js#login-error— hidden by default; shows validation errors
💡 Tip: Use meaningful
id attributes — JavaScript will select these elements with document.getElementById(). IDs must be unique on the page.Chat screen (#chat-screen)
Has class hidden initially. JavaScript removes this class after a successful join.
#room-title— shows current room name in header#typing-indicator— “Alex is typing…” (bonus feature)#online-users— sidebar list of connected usernames#messages— scrollable container where chat bubbles appear#message-input+#send-btn— compose area
Scripts at the bottom
Order matters:
/socket.io/socket.io.js— automatically served by Socket.IO (do not download manually)client.js— our custom logic (Lesson 6)
⚠️ Common Mistake: Putting
<script> tags in <head> before the HTML elements exist. Our scripts are at the bottom of <body> so all elements are loaded first.Accessibility notes
aria-live="polite"on messages — screen readers announce new messagesaria-labelon online users sectionautocomplete="off"on chat inputs — prevents browser autofill interfering
👨🏫 Teaching note: Ask students to open
index.html directly in the browser (file://). It will look unstyled and broken — explain why we need Express to serve it via http://localhost:3000.Checkpoint
- ✅ File saved at
public/index.html - ✅ Both screens exist: login + chat
- ✅ Socket.IO script tag uses
/socket.io/socket.io.js
Next lesson: make it beautiful with CSS.