❗CLAIM

May 18, 2026 · View on GitHub

Custom UI Style

Visual Studio Marketplace Version Made with reactive-vscode

Custom UI Style is a VSCode extension that allows you to customize the editor's appearance and behavior by injecting custom CSS and JavaScript. You can unify the global font family, set a background image, modify Electron BrowserWindow options, add your own custom styles and scripts, and even patch files in other VSCode extensions.

  • Works with VSCode 1.120! (Tested on Windows and MacOS)
  • Support Agents window

Warning

This extension works by modifying the VSCode's source css and js files.

❗CLAIM

Untested on Linux and VSCode forks (like Cursor, WindSurf, etc.), and I currently lack the energy to adapt them. If this extension causes issues in your editor, please consider using these more mature alternative extensions

Features

  • Unify the global font family for the editor and webviews.
  • Set a background image for the editor window.
  • Apply custom stylesheets to both the editor and webviews.
  • Configure Electron BrowserWindow options.
  • Support for restarting VSCode to apply changes.
  • Suppress the "Your Code installation is corrupt" message.
  • Load external CSS and JavaScript files.
  • Patch files in other extensions.

Usage

  1. Backup: When you first install the extension or after a VSCode update, you'll be prompted to create a backup of the original files. This is important for rollback.
  2. Configure: Add your customizations to your settings.json file. See the Example and Configurations sections for details.
  3. Apply: Open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P) and run Custom UI Style: Reload to apply your changes.
  4. Rollback: To revert all changes and restore the original VSCode files, run Custom UI Style: Rollback from the Command Palette.

Example

Available CSS Variables:

  • --cus-mono: Target monospace font family
  • --cus-sans: Target sans-serif font family

Deprecated variables:

  • --cus-monospace-font: Target monospace font family
  • --cus-sans-font: Target sans-serif font family
{
  // Electron BrowserWindow options
  //  - https://www.electronjs.org/docs/latest/api/base-window
  //  - https://www.electronjs.org/docs/latest/api/browser-window
  "custom-ui-style.electron": {
    // Frameless window (no title bar, no MacOS traffic light buttons)
    //  - "A frameless window removes all chrome applied by the OS, including window controls"
    //  - https://www.electronjs.org/docs/latest/api/base-window#new-basewindowoptions
    //  - https://www.electronjs.org/docs/latest/tutorial/custom-window-styles#frameless-windows
    //  - https://www.electronjs.org/docs/latest/tutorial/custom-title-bar
    "frame": false,
    // Disable rounded corners (MacOS)
    //  - https://www.electronjs.org/docs/latest/api/base-window#new-basewindowoptions
    //  - "Whether frameless window should have rounded corners on MacOS"
    //  - "Setting this property to false will prevent the window from being fullscreenable"
    "roundedCorners": false,
  },
  "custom-ui-style.font.sansSerif": "Maple UI, -apple-system",
  "custom-ui-style.background.url": "file:///D:/image/ide-bg.jpg",
  "custom-ui-style.webview.monospaceSelector": [".codeblock", ".prism [class*='language-']"],
  // Custom stylesheet, support native nest selectors
  "custom-ui-style.stylesheet": {
    "kbd, .statusbar": {
      "font-family": "var(--cus-mono)",
    },
    ".chat-question-carousel-container code": {
      "font-family": "var(--cus-mono) !important",
    },
    "span:not([class*='dyn-rule'])+span[class*='dyn-rule']": {
      "border-top-left-radius": "3px",
      "border-bottom-left-radius": "3px",
    },
    "span[class*='dyn-rule']:has(+span[class*='dyn-rule']+span:not([class*='dyn-rule']))": {
      "border-top-right-radius": "3px",
      "border-bottom-right-radius": "3px",
    },
    ".cdr": {
      "border-radius": "3px",
    },
    ".monaco-findInput .monaco-inputbox": {
      "width": "calc(100% + 6px)",
    },
    ".monaco-workbench .activitybar .monaco-action-bar": {
      "& .action-label": {
        "font-size": "21px !important",
        "&::before": {
          "position": "absolute",
          "z-index": 2,
        },
        "&::after": {
          "content": "''",
          "width": "75%",
          "height": "75%",
          "position": "absolute",
          "border-radius": "6px",
        },
      },
      "& .action-item:hover .action-label": {
        "color": "var(--vscode-menu-selectionForeground) !important",
        "&::after": {
          "background-color": "var(--vscode-menu-selectionBackground)",
        },
      },
      "& .active-item-indicator:before": {
        "border": "none !important",
        "width": "3px !important",
        "height": "calc(100% - 12px) !important",
        "top": "6px !important",
        "border-radius": "4px",
      },
      "& .action-item.checked .active-item-indicator:before": {
        "background": "var(--vscode-activityBar-activeBorder)",
      },
    },
    ".basepanel .composite-bar-container .actions-container > .action-item": {
      "height": "24px",
      "padding": "0 8px !important",
      "border-radius": "4px",
      "align-items": "center",
      "justify-content": "center",
      "&.checked": {
        "background": "color-mix(in srgb, var(--vscode-foreground) 12%, transparent)",
      },
      "& .active-item-indicator:before": {
        "content": "none !important",
      },
    },
    ".monaco-text-button": {
      "border-radius": "4px !important",
    },
    ".monaco-button-dropdown": {
      "& > .monaco-button.monaco-text-button": {
        "border-radius": "4px 0 0 4px !important",
      },
      "& > .monaco-button.monaco-dropdown-button": {
        "border-radius": "0 4px 4px 0 !important",
      },
    },
    ".monaco-workbench>.notifications-center": {
      "border-radius": "8px !important",
    },
  },
}

External Resources (CSS or JS File)

Starting from v0.4.2, you can load external CSS and JavaScript files from local or remote URLs.

Caution

Loading external resources can introduce security risks or cause runtime crashes. Use this feature with caution.

  • All resources are applied to the editor, not webviews.
  • Resources are fetched and merged during reload. Live-watching of files is not supported.
{
  "custom-ui-style.external.imports": [
    // assume the script is ESM format
    "file://D:/data/test.js",
    "file:///Users/yourname/test.js",

    // Variable supports:
    // Load from user home dir
    "file://${userHome}/test.css",
    // Load from environment variable (with optional fallback value)
    "file://${env:your_env_name:optional_fallback_value}/other.js",

    // Remote resources will be downloaded
    {
      // <link rel="stylesheet" href="./external.css"></link>
      // will load before `custom-ui-style.stylesheet`
      "type": "css",
      "url": "https://fonts.googleapis.com/css?family=Sofia",
    },
    {
      // <script src="./external.js"></script>
      "type": "js",
      "url": "https://example.com/test.js",
    },
    {
      // <script src="./external.module.js" type="module"></script>
      "type": "js-module",
      "url": "https://example.com/test.module.js",
    },
  ],
}

Load Strategy

By default, all resources are re-fetched on every reload, and failed fetches are skipped.

To cache resources and avoid re-fetching when custom-ui-style.external.imports is unchanged, set the load strategy to "cache":

{
  "custom-ui-style.external.loadStrategy": "cache",
}

To disable all external resources, set the load strategy to "disable":

{
  "custom-ui-style.external.loadStrategy": "disable",
}

Patch Extension

Find and replace target string or Regexp in extension's file

{
  // "custom-ui-style.extensions.enable": false,
  "custom-ui-style.extensions.config": {
    // extension id
    "github.copilot-chat": [
      {
        // target file path related to extension root
        "filePath": "dist/extension.js",
        // find string (support JavaScript like regexp)
        "find": "/(this._genAIClient=new (\\w+)({apiKey:(\\w+)}));/",
        // replace string
        "replace": "(this._genAIClient=new \$1({apiKey:\$2,httpOptions:{baseUrl:'<path/to/url>'}}));",
      },
    ],
  },
}

FAQ

What is modified?

This extension modifies files in your VSCode installation directory. All modified files are backed up with a .custom-ui-style suffix in the same directory. You can see the full list of modified files in path.ts.

When you reload the configuration, the extension restores the original files from the backup, applies your custom patches, and then reloads the window or restarts the application.

No Effect

If your changes don't seem to apply, you may need to fully restart VSCode.

  • Windows/Linux: Close all VSCode windows and restart the application.
  • macOS: Press Command + Q to quit the application, then restart it.

There are also a guide and a video (macOS) available for more detailed instructions.

Explorer tree cuts off with deeply nested folders

This can happen when using transform on Explorer tree internals. VS Code uses virtual scrolling for the file tree, and these transforms can break visible row calculations.

Avoid using transform on:

  • .explorer-viewlet .split-view-container
  • .explorer-folders-view .monaco-list-rows
  • .explorer-folders-view .monaco-tl-row

Suggestion: use non-layout styles for Explorer customization instead (for example border-radius, background, color, outline, and box-shadow).

See #71 for details and reproduction.

EROFS: read-only file system

If you see this error, it means VSCode is installed on a read-only filesystem (e.g., via Snap or AppImage). This extension needs to write to the installation directory, so you'll need to install VSCode using a different method.

RangeError: Maximum call stack size exceeded

This error can occur due to system permission restrictions. To fix it, you need to change the ownership of the VSCode installation directory.

First, fully close VSCode (Command + Q</_kbd> on macOS). Then, run the following command:

# macOS
sudo chown -R $(whoami) "/Applications/Visual Studio Code.app"

# Linux
sudo chown -R $(whoami) "/usr/local/code"

See #6 for more details.

Fail to render panel

In some VSCode forks like Cursor, the extension detail panel may not render due to a Content Security Policy (CSP) violation. To work around this, you can disable the webview patch:

{
  "custom-ui-style.webview.enable": false
}

Configurations

KeyDescriptionTypeDefault
custom-ui-style.preferRestartPrefer restarting VSCode after updates (always true for VSCode >= 1.95.0)booleanfalse
custom-ui-style.reloadWithoutPromptingReload/restart immediately without a notification promptbooleanfalse
custom-ui-style.watchAutomatically reload window on configuration changes (ignores imports)booleantrue
custom-ui-style.electronElectron BrowserWindow options (see Electron documentation)object{}
custom-ui-style.font.monospaceGlobal monospace font family for editor and webviews (falls back to editor's font)string``
custom-ui-style.font.sansSerifGlobal sans-serif font family for editor and webviewsstring``
custom-ui-style.background.urlFull-screen background image URL (e.g., 'https://', 'file://', 'data:') - not syncedstring``
custom-ui-style.background.syncURLFull-screen background image URL (synced), supports variables like userHomeor{userHome} or {env:VAR:fallback}. Lower priority than 'url'.string``
custom-ui-style.background.opacityBackground image opacity (0 to 1)number0.9
custom-ui-style.background.sizeBackground image size (e.g., 'cover', 'contain')string"cover"
custom-ui-style.background.positionBackground image positionstring"center"
custom-ui-style.external.loadStrategyStrategy for loading external CSS or JS resourcesstring"refetch"
custom-ui-style.external.importsExternal CSS or JS resources; supports variables (userHome,{userHome}, {env:VAR:fallback}) and protocols ('https://', 'file://')array``
custom-ui-style.stylesheetCustom CSS for the editor; supports nested selectorsobject{}
custom-ui-style.agents.stylesheetCustom CSS for Agents window; supports nested selectorsobject{}
custom-ui-style.extensions.enableEnable file patching in other extensionsbooleantrue
custom-ui-style.extensions.configConfiguration for patching extension files (key: extension ID, value: patch config)object{}
custom-ui-style.webview.enableEnable style patching in webviewsbooleantrue
custom-ui-style.webview.removeCSPRemove Content-Security-Policy restrictions in webviewsbooleantrue
custom-ui-style.webview.monospaceSelectorCustom monospace selector for webviewsarray``
custom-ui-style.webview.sansSerifSelectorCustom sans-serif selector for webviewsarray``
custom-ui-style.webview.stylesheetCustom CSS for webviews; supports nested selectorsobject{}

Commands

CommandTitle
custom-ui-style.reloadCustom UI Style: Reload
custom-ui-style.rollbackCustom UI Style: Rollback
custom-ui-style.cleanupCustom UI Style: Rollback, cleanup and restart instantly

Credit

License

MIT