Bonus Features — Typing, Online Users & Timestamps
Good news: if you followed Lessons 3 and 6 exactly, these three features are already built in. This lesson explains each feature, the exact code involved, and how to extend them for homework assignments.
Feature 1 — Typing indicator
Shows “Alex is typing…” when someone presses keys in the message box.
Client change (client.js)
// Emit typing event on every input keystroke
messageInput.addEventListener('input', function () {
socket.emit('typing');
});
// Listen for others typing
socket.on('user-typing', function (data) {
if (data.username === currentUsername) return;
typingIndicator.textContent = data.username + ' is typing…';
typingIndicator.classList.remove('hidden');
clearTimeout(typingTimeout);
typingTimeout = setTimeout(function () {
typingIndicator.classList.add('hidden');
}, 1500);
});
Server change (server.js)
socket.on('typing', function () {
socket.to(socket.room).emit('user-typing', {
username: socket.username
});
});
socket.to(room) excludes the typer — you do not need to see your own typing indicator.
Feature 2 — Online users list
Sidebar in chat header showing who is currently in the room.
Server — track users per room
const rooms = {}; // { general: ['Alice', 'Bob'], random: ['Charlie'] }
// On join-room:
if (!rooms[room]) rooms[room] = [];
if (!rooms[room].includes(username)) rooms[room].push(username);
io.to(room).emit('online-users', rooms[room]);
// On disconnect:
rooms[socket.room] = rooms[socket.room].filter(u => u !== socket.username);
io.to(socket.room).emit('online-users', rooms[socket.room] || []);
Client — render the list
socket.on('online-users', function (users) {
renderOnlineUsers(users);
});
function renderOnlineUsers(users) {
onlineUsersEl.innerHTML =
'<strong>Online (' + users.length + ')</strong><span>' +
users.join(', ') + '</span>';
}
Feature 3 — Message timestamps
Each chat bubble shows when the message was sent.
Server — attach ISO timestamp when broadcasting
io.to(socket.room).emit('receive-message', {
type: 'chat',
username: socket.username,
message: message,
timestamp: new Date().toISOString() // e.g. 2026-05-28T14:30:00.000Z
});
Client — format for local timezone
function formatTime(isoString) {
return new Date(isoString).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
});
}
// In bubble HTML:
'<div class="time">' + formatTime(data.timestamp) + '</div>'
toLocaleTimeString converts UTC ISO string to the user’s local time — 2:30 PM in India, 10:00 AM in London, automatically.
Homework extensions (optional challenges)
| Challenge | Hint |
|---|---|
| Private messages | Emit to specific socket.id instead of room |
| Message history | Store array in server memory; send on join |
| User colors | Hash username → consistent bubble color |
| Profanity filter | Replace bad words on server before broadcast |
Verify all three features
- Two tabs, same room — online count shows 2
- Type without sending — other tab sees typing text
- Send message — time appears under bubble
Next lesson: put your chat on the internet with Railway free hosting.