I’m trying to build a basic “BG Color Changer Chrome Extension” using React.JS.
On selecting a color from the background color picker I want that color to instantly apply to all the elements of webpages except the code blocks & media related elements (like images, thumbnails, videos, of Facebook, YouTube etc.).
My Current Approach:
Here’s my content.js file:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "changeBgColor") {
changeBackgroundColor(message.bgColor);
// Storing the selected color in Chrome storage
chrome.storage.local.set({ backgroundColor: message.bgColor }, () => {
console.log("Background color saved");
});
sendResponse({ success: true });
}
return true;
});
function changeBackgroundColor(bgColor) {
// Selecting all elements
const allElements = document.querySelectorAll("*");
// Selecting code & media elements to exclude
const mediaElements = document.querySelectorAll(
"code, img, video, iframe, canvas, object, picture"
);
// Set to store excluded elements
const excludedElements = new Set();
// Applying "transparent" bg color to media elements
mediaElements.forEach((mediaElement) => {
if (!excludedElements.has(mediaElement)) {
mediaElement.style.setProperty(
"background-color",
"transparent",
"important"
);
excludedElements.add(mediaElement);
}
});
// Applying the selected bg color to non-excluded elements
allElements.forEach((el) => {
if (!excludedElements.has(el)) {
el.style.setProperty("background-color", bgColor, "important");
}
});
}
Here’s my App.jsx file:
export default function App() {
const [bgColor, setBgColor] = useState("#000000");
const changeBgColor = (color) => {
chrome.tabs.query({}, (tabs) => {
tabs.forEach((tab) => {
chrome.tabs.sendMessage(
tab.id,
{ action: "changeBgColor", bgColor: color },
(response) => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
} else if (response && response.success) {
console.log("Bg color changed successfully");
chrome.storage.local.set({ backgroundColor: color });
}
}
);
});
});
};
return (
<div>
<input
type="color"
value={bgColor}
onChange={(e) => {
const selectedColor = e.target.value;
setBgColor(selectedColor);
changeBgColor(selectedColor);
}}
/>
</div>
);
}
Problems:
- When I select a color from the background color picker, the selected background color instantly applies to all elements including code blocks and media related elements (like images, videos, thumbnails etc.) and then after refreshing the page, code blocks & media related elements are excluded from the background color along with some other non-code, non-media elements such as divs & anchor links etc.
- Every time I reload the page, I experience a random inconsistent behavior (don’t know how to explain it). Sometimes the background color is applying to all the elements including code blocks & media related elements as well while at other times it excludes them along with some other non-code, non-media elements.
What I tried:
First, I attempted to select all the HTML elements whose background color I wanted to change by explicitly mentioning their names (e.g., body, div, span, button, input, etc.). However, this didn’t work, as many elements on websites like YouTube and Facebook remained uncolored despite naming them.
Next, I tried selecting all elements while excluding code blocks and media-related elements, without applying any inline (!important) styling to the excluded elements. Unfortunately, this also failed, as selecting a color from the background color picker instantly applied it to all elements, without excluding code blocks and media-related elements.