Back
Chapter 7

Changing Icons Programmatically

View Source Code

We can see that WXT framework already has a default icon and actually a default popup title so maybe it’s the perfect time to give it some better values

If I come to the WXT config I can see that in the manifest I could probably add the name

A version just let’s call it 1.0.0 and the description add notes to any tab in your browser

Alright I can already see it’s TabNotes but it’s still quite default popup title so actually it’s not only changed there but I go to the popup and I also need to change it here

This is one of those cases when it seems like I need to refresh so I’ll just stop and run again

I can bun dev or npm dev or whatever you’re using and now it’s TabNotes

It’s perfect but we wanted to talk about the icons right

Icon sizes

If I look at the output bundle I can see that there are five sizes of the icon 16 32 48 96 and 128

And if I come to my public folder I see that these files are there as well

So WXT framework just copies over the contents of this public folder into the output

This wxt.svg we will not need and let’s create five sizes for the icon

I already created two icons one for the empty state and one when the page has notes assigned to it

I want to save the empty one as the icon

To create the five sizes I can manually export them in five different sizes which is not too complicated or I can use a tool called favicomatic.com

This tool basically generates icons in all the sizes that you ask them to

And if I look at my code base I saw that I need 16 32 48 96 and 128

The rest I can leave as it is and I’ll just drag it over

As you can see it already downloaded the results in a zip

And if I open it I can see that it has all the five files

And there’s a glitch because the 48x48 file is in an ico format which is fine but I need pngs so I have to still export it manually

Which I did I can just rename the files 16 32 and copy them over instead of the current icons

I also created the 48 version so I’ll just copy and paste it as well

As you can see this is another case when our extension broke so I can just stop the dev command and start again

And very nice we have this icon here

Not only here but if I go to the chrome extension page I can see that that is the icon that is being used with the extension

So far so good

We replaced the generic icon with one that’s more relevant to our extension

But what I really want to do is change the icon dynamically based on whether the page has notes or not

Changing icons dynamically

So let’s see how can we do that

I’ll create a function that changes the icon based on whether notes exist for the current tab

import { storage } from 'wxt/storage';
import getPageKey from '@/utils/getPageKey';

const changeIcon = async (tabId: number) => {
  const tab = await browser.tabs.get(tabId);
  if (!tab.url) return;
  
  const pageKey = getPageKey(tab.url);
  const notesStorage = await storage.getItem('sync:notesStorage');
  const noteData = notesStorage?.[pageKey];
  
  if (noteData) {
    // Has notes - show full icon
    await browser.action.setIcon({
      tabId,
      path: {
        "16": "icon-full/16.png",
        "32": "icon-full/32.png",
        "48": "icon-full/48.png",
        "96": "icon-full/96.png",
        "128": "icon-full/128.png"
      }
    });
  } else {
    // No notes - show empty icon
    await browser.action.setIcon({
      tabId,
      path: {
        "16": "icon/16.png",
        "32": "icon/32.png",
        "48": "icon/48.png",
        "96": "icon/96.png",
        "128": "icon/128.png"
      }
    });
  }
};

Now I need to call this function when notes are saved

So in my popup when the user types I’ll update the icon

noteText.addEventListener('keyup', async () => {
  const [tab] = await browser.tabs.query({ 
    active: true, 
    currentWindow: true 
  });
  
  if (!tab.id || !tab.url) return;
  
  // Save note logic here...
  
  // Update icon
  await changeIcon(tab.id);
});

Perfect

Now when you type a note the icon changes to show that this page has notes

And when you delete the note the icon changes back to empty

The problem

But there’s a problem

The icon only changes when you type in the popup

It doesn’t change when you switch tabs

So if you go to a page that already has notes the icon still shows empty

We need to detect tab changes and update the icon accordingly

That’s what we’ll do in the next chapter

What’s next

We’ve set up dynamic icons that change based on whether notes exist

But we need to update them when tabs change too

In the next chapter we’ll add tab change detection to keep the icon in sync