DEV Community

Cover image for Real-Time Notifications UI with Tailwind CSS and WebSockets
HexShift
HexShift

Posted on

Real-Time Notifications UI with Tailwind CSS and WebSockets

Adding real-time features to your web app can significantly boost engagement by instantly informing users without page reloads. In this tutorial, we’ll build a notification dropdown panel using Tailwind CSS for styling and WebSockets for live updates—framework-agnostic and easy to copy into any stack.


Why Real-Time Notifications?

  • Keeps users updated instantly
  • Improves engagement with live feedback
  • Enhances UX by avoiding manual refreshes

HTML & Tailwind Setup

<div class="relative">
  <button id="notif-btn" class="relative p-2 focus:outline-none">
    🔔
    <span id="notif-count" class="absolute -top-1 -right-1 bg-red-600 text-white text-xs w-5 h-5 rounded-full flex items-center justify-center hidden">!</span>
  </button>
  <div id="notif-panel" class="hidden absolute right-0 mt-2 w-80 bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden max-h-96 overflow-y-auto transition-opacity duration-200">
    <!-- Notifications go here -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
  • Wrapper is relative, panel is absolute for floating
  • Badge uses bg-red-600, rounded-full, and position utilities
  • Panel styled with shadow-lg, rounded-lg, and scrollable behavior

WebSocket Integration

const btn = document.getElementById('notif-btn');
const panel = document.getElementById('notif-panel');
const count = document.getElementById('notif-count');
let unseen = 0;

btn.addEventListener('click', () => {
  panel.classList.toggle('hidden');
  if (!panel.classList.contains('hidden')) {
    unseen = 0;
    count.classList.add('hidden');
  }
});

// Initialize WebSocket (add your own URL)
const ws = new WebSocket('wss://your.api/notifications');
ws.onmessage = (e) => {
  const data = JSON.parse(e.data);
  const item = document.createElement('div');
  item.className = 'flex items-start px-4 py-3 border-b border-gray-200 dark:border-gray-700';
  item.innerHTML = `
    <div class="flex-1">
      <p class="font-semibold text-gray-800 dark:text-gray-100">${data.title}</p>
      <p class="text-sm text-gray-600 dark:text-gray-300">${data.message}</p>
      <p class="text-xs text-gray-400">${data.timestamp}</p>
    </div>`;
  panel.prepend(item);
  unseen += 1;
  count.textContent = unseen;
  count.classList.remove('hidden');
};
Enter fullscreen mode Exit fullscreen mode
  • Toggles visibility via hidden class
  • WebSocket listens for JSON messages, prepends notifications
  • Increment badge count for unseen messages

Responsive & Interactive Touches

  • Use w-full sm:w-80 for mobile adaptability
  • Add transition-opacity duration-200 for smooth panel appearance
  • Make badge smaller on mobile if needed with responsive text sizing

Accessibility Recommendations

  • Ensure badge has aria-label="X new notifications" updated on change
  • Manage focus: return focus to button after opening/closing
  • Use roles like role="menu" and aria-expanded on button

About the 37‑Page PDF Guide

If you're building real-time UIs or complex interactive components, Mastering Tailwind at Scale: Architecture, Patterns & Performance dives deep into:

  • Component structure patterns for dynamic systems
  • Theming, utility scoping, and responsive design at scale
  • Performance tuning for both CSS and JavaScript
  • Integration patterns with frameworks (React, Vue, etc.), WebSockets, backend services, and WASM
  • Practical examples and architecture blueprints covering real-time features like notifications

This 37‑page guide is on Gumroad for $10, giving you detailed diagrams, reusable snippets, and strategies to scale your Tailwind-powered frontend consistently and efficiently.

👉 Get the guide here:

Mastering Tailwind at Scale: Architecture, Patterns & Performance


Give your users feedback that feels instantaneous and polished—build live notifications with Tailwind and WebSockets today!

Top comments (0)