Detect whether two tabs are opened in JavaScript

Detect whether two tabs are opened in JavaScript

Written by Posandu Mapa on Jan 5th, 2023 Views Report Post

If you ever used WhatsApp Web, you might have noticed that it shows a warning if you open the same account in two different tabs.

I wondered how they did it, so I decided to research it and found out that it's actually quite simple.

The BroadcastChannel API

The MDN documentation says that the BroadcastChannel API is a simple way to communicate between different tabs.

Think of it as a person who gets a message from you and then tells it to another person.

Tab 1 sends a message to the BroadcastChannel and then the BroadcastChannel sends the message to Tab 2. Tab 2 listens to the BroadcastChannel when it receives a message.

How to use it

We'll create a simple HTML file with two buttons.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script src="https://cdn.tailwindcss.com/3.2.4"></script>
        <!-- TODO: Make your own UI framework -->
    </head>
    <body>
        <div class="min-h-screen bg-slate-100 flex justify-center items-center">
            <div class="px-8 py-4 bg-white shadow-md rounded">
                <h1 class="msg text-2xl">I'm only opened in this tab 😢</h1>

                <a
                    href="#"
                    class="mt-4 block text-center p-2 bg-blue-600 rounded text-white hover:bg-blue-700 text-sm"
                    onclick="window.opened = window.open('index.html', 'my-window')"
                >
                    Open in another tab
                </a>

                <a
                    href="#"
                    class="mt-4 block text-center p-2 bg-gray-100 rounded text-gray-900 hover:bg-gray-200 text-sm"
                    onclick="(window.opened ? window.opened.close() : window.close()), window.opened = null"
                >
                    Close that tab
                </a>
            </div>
        </div>

        <script>
            // Your code here
        </script>
    </body>
</html>

The fronted uses Tailwind CSS for styling, but you can use any other CSS framework or even write your own CSS. So, the page looks like this:

Now, here's the scripting part. We first create a constant to select the .msg element.

const msg = document.querySelector(".msg");

Then we create a broadcast channel to communicate.

const bc = new BroadcastChannel("my-channel");

We first emit the open event that fires when the page loads.

// Send a message to the other tab
bc.postMessage("open");

Then we listen to the message event that fires when the BroadcastChannel receives a message.

bc.onmessage = ({ data }) => {
    if (data === "open") {
        // If the other tab is opened
        bc.postMessage("yes"); // We send a message to the other tab
        msg.textContent = "I'm opened in another tab 😄";
    } else if (data === "yes") {
        // If we receive a message from the other tab
        msg.textContent = "I'm opened in another tab 😄";
    } else {
        msg.textContent = "I'm only opened in this tab 😢"; // Reset the message
    }
};

Now if you open the page in two different tabs, you'll see that the message changes but, if you close one of the tabs, the message will not change. That's because we didn't emit the close event. So, we'll add a beforeunload event listener to the window that fires when the page is about to be closed.

// Close the channel when the tab is closed
window.addEventListener("beforeunload", () => {
    bc.postMessage("close");
    bc.close();
});

Now, if you open the page in two different tabs and close one of them, the message will change.

Conclusion

And, that's it! You can use this to make something like WhatsApp Web.

Here's the full code.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <link rel="stylesheet" href="style.css" />
    </head>
    <body>
        <div class="min-h-screen bg-slate-100 flex justify-center items-center">
            <div class="px-8 py-4 bg-white shadow-md rounded">
                <h1 class="msg text-2xl">I'm only opened in this tab 😢</h1>

                <a
                    href="#"
                    class="mt-4 block text-center p-2 bg-blue-600 rounded text-white hover:bg-blue-700 text-sm"
                    onclick="window.opened = window.open('index.html', 'my-window')"
                >
                    Open in another tab
                </a>

                <a
                    href="#"
                    class="mt-4 block text-center p-2 bg-gray-100 rounded text-gray-900 hover:bg-gray-200 text-sm"
                    onclick="(window.opened ? window.opened.close() : window.close()), window.opened = null"
                >
                    Close that tab
                </a>
            </div>
        </div>

        <script>
            const msg = document.querySelector(".msg");

            // Listen for the message event
            const bc = new BroadcastChannel("my-channel");

            bc.onmessage = ({ data }) => {
                if (data === "open") {
                    bc.postMessage("yes");
                    msg.textContent = "I'm opened in another tab 😄";
                } else if (data === "yes") {
                    msg.textContent = "I'm opened in another tab 😄";
                } else {
                    msg.textContent = "I'm only opened in this tab 😢";
                }
            };

            // Send a message to the other tab
            bc.postMessage("open");

            
            // Close the channel when the tab is closed
            window.addEventListener("beforeunload", () => {
                bc.postMessage("close");
                bc.close();
            });
            
        </script>
    </body>
</html>

Also wish you a very happy new year! 🎉🎉🎉

Resources

Connect with me

Comments (0)