Framework
Styling

Styling Plasmo CSUI

Plasmo CSUI's built-in Root Container allows extension developers to safely style their components. It ensures that for the most part:

  • The exported style does not leak to the web page
  • The web page's style does not influence the component's styling

See caveats for when it does not work.

Raw CSS Text

To style your CSUI, export a getStyle function:

content.tsx
import type { PlasmoGetStyle } from "plasmo"
 
export const getStyle: PlasmoGetStyle = () => {
  const style = document.createElement("style")
  style.textContent = `
    p {
      background-color: yellow;
    }
  `
  return style
}

Import Stylesheet

To import CSS/LESS/SASS files, combine the getStyle API with the data-text import scheme:

content.tsx
import styleText from "data-text:./style.scss"
import type { PlasmoGetStyle } from "plasmo"
 
export const getStyle: PlasmoGetStyle = () => {
  const style = document.createElement("style")
  style.textContent = styleText
  return style
}

CSS-in-JS

The getStyle API can also be used to hydrate CSS-in-JS style cache, for example when using with emotion (opens in a new tab):

content.tsx
import createCache from "@emotion/cache"
import { CacheProvider } from "@emotion/react"
import type { PlasmoGetStyle } from "plasmo"
 
const styleElement = document.createElement("style")
 
const styleCache = createCache({
  key: "plasmo-emotion-cache",
  prepend: true,
  container: styleElement
})
 
export const getStyle: PlasmoGetStyle = () => styleElement

CSS Modules

To utilize CSS modules, import the stylesheet twice:

content.tsx
import styleText from "data-text:./style.module.pcss"
import type { PlasmoCSConfig } from "plasmo"
 
import * as style from "./style.module.pcss"
 
export const getStyle = () => {
  const style = document.createElement("style")
  style.textContent = styleText
  return style
}
 
const Overlay = () => <h1 className={style.header}>Captain Log</h1>
 
export default Overlay

Custom Font

To use a custom font in your CSUI, you must import the font inside a CSS file and declare it in the css property of the config object. The browser does not recognize Font assets if declared inside a ShadowDOM. You have to load them in the global scope.

  1. Add your font in the assets directory (e.g /assets/Fascinate.woff2)
  2. Create a font.css file next to your content script, importing the font inline using the data-base64 scheme:
font.css
@font-face {
  font-family: "Fascinate";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(data-base64:~assets/Fascinate.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
  1. Declare the file in the css property of the content script config:
content.tsx
export const config: PlasmoCSConfig = {
  matches: ["https://www.plasmo.com/*"],
  css: ["font.css"]
}
  1. Once the browser registers the font, you can reference it inside your CSS style:
style.css
.hw-top {
  background: red;
  color: white;
  font-family: "Fascinate";
}

See with-content-scripts-ui/contents/plasmo-overlay.tsx (opens in a new tab) for a full example.

Styling the Shadow DOM

Use the IDs #plasmo-shadow-container and plasmo-inline to alter the Root Container styles in your CSS:

style.css
#plasmo-shadow-container {
  z-index: 99999;
}
 
#plasmo-inline {
  background: blue;
}
⚠️

See Caveats: Root Container Style if some styling rules are not being overridden.

Inherit the Web Page's Style

To inherit the web page's style, override the built-in Root Container to mount your component directly into the web page's DOM. Click here for more details.

Caveats

There are many situations that the framework's generic style encapsulation cannot handle (yet). Here are some common gotchas:

CSS Variables

CSS Variables are shared across every frame within the same browser tab. This means that if the webpage declares some CSS variables at the :root context, it will be prioritized over yours.

To mitigate CSS variable sharing between CSUI and the web page, you can either:

  • Declare a unique prefix namespace for your CSS variables
  • Hoist your CSS variable under a :host scope
  • Mount your component inside an iframe, with its own head and body

Root Container Style

If the host webpage uses a global * specifier to style its page, it can potentially override the Root Container style. For example:

* {
  display: block;
}

The above code will cause the root container to have block display. In cases like these, overriding the root container style with an inline style will help keep the container consistent.

There may exist some CSS styling declarations that cannot be overridden to alter the the Root Container styles. In those cases, the !important flag can be used as a workaround.

style.css
#plasmo-shadow-container {
  z-index: 2147483646 !important;
}