Skip to content

Instantly share code, notes, and snippets.

@panayotoff
Created March 12, 2026 22:38
Show Gist options
  • Select an option

  • Save panayotoff/f2fca72a76b2d80ab74405ebe1863fc6 to your computer and use it in GitHub Desktop.

Select an option

Save panayotoff/f2fca72a76b2d80ab74405ebe1863fc6 to your computer and use it in GitHub Desktop.
useBroadcastChannel React/Typescript hook
import { useCallback, useEffect, useRef, useState } from "react";
type UseBroadcastChannelOptions<T> = {
onMessage?: (message: T) => void;
onError?: (error: Error | Event) => void;
echo?: boolean; // whether sent messages should also be added locally
};
const isSupported =
typeof window !== "undefined" && "BroadcastChannel" in window;
const useBroadcastChannel = <T = string>(
topic: string,
options: UseBroadcastChannelOptions<T> = {}
) => {
const { onMessage, onError, echo = false } = options;
const [messages, setMessages] = useState<T[]>([]);
const channelRef = useRef<BroadcastChannel | null>(null);
useEffect(() => {
if (!isSupported) {
onError?.(new Error("BroadcastChannel is not supported in this environment."));
return;
}
let channel: BroadcastChannel;
try {
channel = new BroadcastChannel(topic);
channelRef.current = channel;
} catch (error) {
onError?.(error instanceof Error ? error : new Error("Failed to create BroadcastChannel."));
return;
}
const handleMessage = (event: MessageEvent<T>) => {
setMessages(prev => [...prev, event.data]);
onMessage?.(event.data);
};
const handleMessageError = (event: MessageEvent) => {
onError?.(event);
};
channel.addEventListener("message", handleMessage);
channel.addEventListener("messageerror", handleMessageError);
return () => {
channel.removeEventListener("message", handleMessage);
channel.removeEventListener("messageerror", handleMessageError);
channel.close();
if (channelRef.current === channel) {
channelRef.current = null;
}
};
}, [topic, onMessage, onError]);
const sendMessage = useCallback(
(msg: T) => {
const channel = channelRef.current;
if (!channel) {
onError?.(new Error("BroadcastChannel is not initialized."));
return false;
}
try {
channel.postMessage(msg);
if (echo) {
setMessages(prev => [...prev, msg]);
}
return true;
} catch (error) {
onError?.(error instanceof Error ? error : new Error("Failed to post message."));
return false;
}
},
[echo, onError]
);
const clearMessages = useCallback(() => {
setMessages([]);
}, []);
return {
messages,
sendMessage,
clearMessages,
isSupported,
};
};
export default useBroadcastChannel;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment