Content Scripts UI

Content Script UI

Plasmo has first-class support for mounting a React component, a Svelte3 component, or a Vue3 component into the current webpage. This feature is called content scripts UI (CSUI).

An extension can have as many CSUI as needed, with each CSUI targeting a group of webpage or a specific webpage by exporting the config object. To start injecting UI using React:

  1. Create a new content script inside contents directory with the .tsx extension
  2. Export default a React component
  3. Profit 🎉

NOTE: It works with a content.tsx at the root source code directory as well.

See with-content-scripts-ui

How does Plasmo mount the React component?

Plasmo creates a Shadow DOM and mounts the React component to it. This isolation technique prevents the web page's style from affecting the component's styling.


To mount/anchor a React component on top of a specific element on the current webpage, export a function called getMountPoint that returns a valid HTMLElement:

export const getMountPoint = async () => document.querySelector("#element")

This function is asynchronous, which allows you to wait until the element exists. It is also agnostic. You can send the current webpage to a remote API via fetch to calculate the element selector, then query and return that element. The possibilities are endless!

Check this file in with-content-scripts-ui for an example.

How does getMountPoint anchor the React component?

getMountPoint first listens to the current window's scroll event. On each scroll event, it uses the getBoundingClientRect function to calculate the absolute position of the target element. Then, it applies the calculated position to the container used to mount your component.


To inject stylesheets into your content script UI's Shadow DOM or anywhere in the current webpage, export a getStyle function that returns a valid element:

import cssText from "data-text:~/contents/plasmo-overlay.css"

export const getStyle = () => {
  const style = document.createElement("style")
  style.textContent = cssText
  return style

Plasmo appends the style element into the Shadow DOM before the exported component's container.

See the plasmo-overlay.tsx file in with-content-scripts-ui for an example.

Note about data-text schemes

In the example above, we use the data-text scheme to load our stylesheet as plain text into the cssText variable, which we then assign to our style element's textContent. Be cautious with this scheme's import path if you use the src directory, as noted here.

Styling the built-in shadow containers

Use the ids #plasmo-mount-container and #plasmo-shadow-container to tweak the style of these shadowDOM containers in your css:

#plasmo-shadow-container {
  z-index: 99999;

#plasmo-mount-container {
  background: blue;


There are cases when we might want to make run-time change to the shadow host. By exporting a getShadowHostId function (optionally async), we can assign the shadow host's DOM ID, which will allow us to select and modify it:

export const getShadowHostId = () => "custom-shadow-host"


To replace the Shadow DOM, export a getRootContainer function that returns a valid HTMLElement.

Use cases:

export const getRootContainer = () => {
  return document.querySelector("#feature")

NOTE: If you export a getRootContainer function, Plasmo ignores the getStyle function since only the provided Shadow DOM container uses it. getMountPoint's behavior might also be affected as the component's position will be relative to your provided container.

Check this file in with-content-scripts-ui for an example.

Last updated on July 24, 2022