Svelte

Build extension UIs with Svelte components while keeping Extension.js in charge of the framework wiring.

Extension.js detects Svelte from your project dependencies and configures .svelte resolution, loader setup, and Svelte client aliases automatically.

When Svelte is a good fit

  • You want a smaller runtime for popup, options, sidebar, or new-tab UIs.
  • You prefer component-first authoring with concise syntax.
  • You want a framework option that works for both extension pages and content-script UI mounts.

Template example

new-svelte

Use the Svelte starter when you want a framework-first extension UI with minimal setup.

npm
pnpm
yarn
npx extension@latest create my-extension --template=new-svelte

Usage with an existing extension

Install Svelte:

npm
yarn
pnpm
bun
deno
npm install svelte

For explicit setup in an existing project, install the Svelte loader too:

npm
yarn
pnpm
bun
deno
npm install -D svelte-loader typescript

Development behavior

When Svelte is detected, Extension.js:

  • enables .svelte file resolution
  • wires the Svelte loader into the JS framework pipeline
  • applies Svelte client aliases such as svelte, svelte/store, and svelte/reactivity

If optional tooling is missing, Extension.js can install what it needs and ask for a restart.

Usage examples

In an extension page

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Svelte Extension</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
  <script src="./main.ts"></script>
</html>
import App from './App.svelte'

new App({
  target: document.getElementById('app')!
})

In a content script

For content scripts, create a mount node and return a cleanup from your default export so Extension.js can remount safely in development:

import App from './App.svelte'

export default function main() {
  const target = document.createElement('div')
  target.id = 'extension-root'
  document.body.appendChild(target)

  const app = new App({target})

  return () => {
    app.$destroy()
    target.remove()
  }
}

Best practices

  • Keep Svelte components focused on UI and move browser API orchestration to dedicated modules.
  • In content scripts, always return cleanup so remount behavior stays predictable.
  • Use Svelte for extension pages first, then expand to content-script UI once the feature boundary is clear.

Next steps