DEV Community

WDSEGA
WDSEGA

Posted on

Component Deep Dive #33: Notification Dropdown — Bell, Badge, List, Read State

Component Deep Dive #33: Notification Dropdown

The difficulty of notification systems isn't the frontend — it's state synchronization: read, unread, count, all three must stay consistent.

Click-Outside-to-Close

Three close paths: toggle on trigger click, close on outside click, close on Escape. e.stopPropagation() prevents the event from bubbling to document — otherwise clicking the trigger opens then immediately closes.

After Escape close, return focus to the trigger — this is an accessibility requirement.

Rendering + Relative Time

function timeAgo(timestamp) {
  const diff = Date.now() - timestamp;
  if (diff < 60000) return 'Just now';
  if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
  if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
  return `${Math.floor(diff / 86400000)}d ago`;
}
Enter fullscreen mode Exit fullscreen mode

Mark as Read

Optimistic Update is best practice for notification systems — update UI first, then sync to server. Users feel "instant marking" instead of waiting for network spinners. On failure, silently roll back — notification marking isn't a critical operation.

Unread Count Sync

Each markAsRead call updates the badge. Badge visibility is controlled by CSS (data-count="0"display: none), JS only updates the value.

Polling New Notifications

Pause polling when panel is open — user is already viewing notifications, no need to fetch more. Resume when closed.

Common Pitfalls

  1. Don't forget stopPropagation — otherwise trigger click opens then closes immediately
  2. Return focus to trigger after Escape — accessibility requirement
  3. Optimistic update + failure rollback — don't show errors for non-critical operations
  4. Pause polling when panel is open — no need to fetch while user is viewing
  5. Relative time needs periodic refresh — "5m ago" should become "1h ago" after an hour

This article was originally published on Deskless Daily.

Top comments (0)