Injecting elements in a page #1958
-
|
Hello, I am new to WXT I was just exploring it. But it target's youtube's whole UI. Like the youtube logo isn't showing, the player icon's wasn't showing. Can anyone help me what I am doing wrong? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
|
@ptdatta the issue is WXT's default two things to fix:
export default defineContentScript({
matches: ["*://*.youtube.com/*"],
cssInjectionMode: "ui",
async main(ctx) {
// your code here
},
});
if you don't need any custom CSS at all, the key insight is that the default |
Beta Was this translation helpful? Give feedback.
-
|
@sunnypatell is absolutely right. I was playing with your code and added some performance optimizations. import ReactDOM from 'react-dom/client';
export default defineContentScript({
matches: ['*://*.youtube.com/*'],
cssInjectionMode: 'ui',
main() {
const mountedCards = new WeakMap<HTMLElement, ReactDOM.Root>();
const injectButton = (card: HTMLElement) => {
if (mountedCards.has(card)) return;
const menu = card.querySelector<HTMLElement>('.yt-lockup-metadata-view-model__menu-button');
if (!menu) return;
// Create host
const host = document.createElement('div');
host.style.display = 'inline-block';
menu.insertAdjacentElement('afterend', host);
// Shadow DOM
const shadow = host.attachShadow({ mode: 'open' });
// Inject styles
const style = document.createElement('style');
style.textContent = `
:host {
all: initial;
}
.wrapper {
display: inline-flex;
align-items: center;
}
button {
background: #ff0000;
color: white;
border: none;
padding: 6px 12px;
border-radius: 8px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
}
button:hover {
background: #cc0000;
}
`;
shadow.appendChild(style);
const mountPoint = document.createElement('div');
mountPoint.className = 'wrapper';
shadow.appendChild(mountPoint);
const root = ReactDOM.createRoot(mountPoint);
root.render(<button>🔥</button>);
mountedCards.set(card, root);
};
// Throttled observer
let scheduled = false;
const observer = new MutationObserver(() => {
if (scheduled) return;
scheduled = true;
requestAnimationFrame(() => {
const cards = document.querySelectorAll<HTMLElement>('ytd-rich-item-renderer');
cards.forEach(injectButton);
scheduled = false;
});
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
// Initial run
document.querySelectorAll<HTMLElement>('ytd-rich-item-renderer').forEach(injectButton);
},
}); |
Beta Was this translation helpful? Give feedback.

@ptdatta the issue is WXT's default
cssInjectionModewhich is"manifest". this causes all CSS from your content script bundle (including any CSS imports, tailwind base styles, resets, etc.) to be injected globally into YouTube's page via the manifest'scssarray. that overrides YouTube's own styles, breaking the entire UI.two things to fix:
cssInjectionModeto"ui"or"manual"to prevent global CSS injection:createShadowRootUiinstead of rawReactDOM.createRootto isolate your injected UI's styles inside a Shadow DOM. this preve…