Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 1080432 of Comparison with XUL/XPCOM extensions

  • Revision slug: Mozilla/Add-ons/WebExtensions/Comparison_with_XUL_XPCOM_extensions
  • Revision title: Comparison with XUL/XPCOM extensions
  • Revision id: 1080432
  • Created:
  • Creator: wbamberg
  • Is current revision? No
  • Comment

Revision Content

{{AddonSidebar}}

This article is a technical comparison between WebExtensions and "classic" extensions developed using direct XUL manipulation and direct access to XPCOM. It's intended to help orient people who maintain an add-on like this, and who are planning to port the add-on to WebExtensions.

This article covers both overlay extensions and bootstrapped extensions, but not extensions developed using the Add-on SDK. For the Add-on SDK, please see Comparison with the Add-on SDK.

At a very basic level, XUL/XPCOM extensions are similar to WebExtensions. They both include:

  • manifest files defining metadata for the add-on and some aspects of its behavior.
  • JavaScript code that gets access to a set of privileged JavaScript APIs and that stays loaded for as long as the add-on itself is enabled.
  • the ability to add specific UI elements, such as buttons, to the browser.

Beyond that, though, the systems are very different. In particular:

  • Compared with XUL/XPCOM extensions, WebExtensions provide much more limited options for the add-on's UI, and a much more limited set of privileged JavaScript APIs.
  • WebExtensions don't get direct access to web content (note, though, that this is also true of XUL/XPCOM extensions that expect to work with multiprocess Firefox).

Manifest

XUL/XPCOM extensions have two manifest files:

  • the install.rdf contains metadata about the extension such as its name, icons, and so on
  • the chrome.manifest, that tells Firefox where it can find the components of the extension, including XUL overlays for the extension's interface, scripts for its behavior, and files containing localized strings.

WebExtensions have a single manifest file called manifest.json, that has a similar purpose. You use it to specify the add-on's name, description, icons, and so on, as well as to specify any buttons it adds to Firefox and to list scripts it needs to run. To get an overview of the components of a WebExtension, and how they are specified in manifest.json, see "Anatomy of a WebExtension".

Learn more

UI

XUL/XPCOM extensions can build their UI by directly manipulating the XUL used to specify the browser's own UI. They do this either using overlays or, in the case of bootstrapped/restartless extensions, using JavaScript to modify the XUL document. They can not only add any elements to the browser's UI, they can also modify or remove existing elements. They can also use APIs like CustomizableUI.jsm to build their UI.

WebExtensions don't get this kind of direct access. Instead, a combination of manifest.json keys and JavaScript APIs enable them to add a limited set of UI components to the browser. The available components are:

Name Description Specified using
Browser action Button in the browser toolbar, with an optional popup panel.

browser_action manifest key

browserAction API

Page action Button in the URL bar, with an optional popup panel.

page_action manifest key

pageAction API

Commands Keyboard shortcuts.

commands manifest key

commands API

Context menu Adds items and submenus to the browser's context menu. contextMenus API

Privileged APIs

Both XUL/XPCOM extensions and WebExtensions can contain scripts that stay loaded for as long as the extension itself is enabled, and that have access to a set of privileged APIs. However, XUL/XPCOM extensions get access to a much wider range of APIs.

The scripts packaged with XUL/XPCOM extensions get access to the full set of XPCOM APIs and JavaScript code modules through the Components object. They also get direct access to the browser's internals through globals like gBrowser.

The equivalent WebExtension scripts are called background scripts, and they get access to a much smaller set of high-level JavaScript APIs. To see all the privileged APIs available to background scripts, see the summary API page. Background scripts also get a window global, with all the DOM objects that are available in a normal web page.

There are vastly more APIs available to XUL/XPCOM extensions than are available to WebExtensions, and for many XUL/XPCOM APIs, there isn't a WebExtensions substitute. The table below lists every API in the popular Services.jsm module, describe what the equivalent WebExtensions API would be, if there is one.

Services.jsm API WebExtensions equivalent
{{ interface("nsIAndroidBridge") }} None
{{ interface("nsIXULAppInfo") }}
{{ interface("nsIXULRuntime") }}
None
{{ interface("nsIAppShellService") }} None
{{ interface("nsIBlocklistService") }} None
{{ interface("nsICacheService") }} None
{{ interface("nsICacheStorageService") }} None
{{ interface("nsIClipboard") }} None
{{ interface("nsIConsoleService") }} window.console
{{ interface("nsIContentPrefService") }} None
{{ interface("nsICookieManager2") }} cookies
{{ interface("nsIMessageSender") }} Content scripts
CrashManager.jsm  
{{ interface("nsIDirectoryService") }}
{{ interface("nsIProperties") }}
Directory service
{{ interface("nsIDOMStorageManager") }} DOM Storage Manager
{{ interface("nsIDOMRequestService") }} DOMRequest service
{{ interface("nsIDownloadManager") }} Download manager
{{ interface("nsIDroppedLinkHandler") }} Dropped link handler service
{{ interface("nsIEventListenerService") }} Event listener service
{{ interface("nsIEffectiveTLDService") }} EffectiveTLD service
{{ interface("nsIFocusManager") }} Focus manager
{{ interface("nsIIOService") }}
{{ interface("nsIIOService2") }}
I/O Service
{{ interface("nsILocaleService") }} Locale service
{{ interface("nsILoginManager") }} Password Manager service
{{ interface("nsIWinMetroUtils") }} 2
{{ interface("nsIMessageBroadcaster") }}
{{ interface("nsIFrameScriptLoader") }}
Global frame message manager3
{{ interface("nsIObserverService") }} Observer service
{{ interface("nsIPermissionManager") }} Permission manager service
{{ interface("nsIMessageBroadcaster") }}
{{ interface("nsIProcessScriptLoader") }}
Global parent process message manager3
{{ interface("nsIPrefBranch") }}
{{ interface("nsIPrefBranch2") }}
{{ interface("nsIPrefService") }}
Preferences service
{{ interface("nsIPromptService") }} Prompt service
{{ interface("mozIJSSubScriptLoader") }} JavaScript subscript loader service
{{ interface("nsIScriptSecurityManager") }} Script security manager
{{ interface("nsIBrowserSearchService") }} Browser search service
{{ interface("nsIAppStartup") }} Application startup service
{{ interface("mozIStorageService") }} Storage API service
{{ interface("nsIStringBundleService") }} String bundle service
{{ interface("nsIPropertyBag2") }} System info service
{{ interface("nsITelemetry") }} Telemetry service
{{ interface("nsIThreadManager") }} Thread Manager service
{{ interface("nsIURIFixup") }} URI Fixup service
{{ interface("nsIURLFormatter") }} URL Formatter service
{{ interface("nsIVersionComparator") }} Version comparator service
{{ interface("nsIWindowMediator") }} Window mediator service
{{ interface("nsIWindowWatcher") }} Window watcher service

Learn more

Interacting with web content

Historically, XUL/XPCOM extensions have been able to get direct access to web content. For example, they can directly access and modify the page DOM using gBrowser:

gBrowser.contentWindow.document.querySelector("h1").innerHTML = "yadda yadda";

However, this is only possible in single-process Firefox. In multiprocess Firefox, web content and add-on code run in different processes, so this direct access is no longer possible, and extensions which rely on it will break. Multiprocess Firefox is coming soon, and multiprocess compatibility will be a necessity.

XUL/XPCOM extensions can still interact with web content in multiprocess Firefox by refactoring the code that accesses web content into separate scripts called frame scripts, and using the message manager to communicate with these scripts. But this is complex and can involve deep changes to the extension's code.

WebExtensions are multiprocess-compatible by default: code that interacts with web content is factored into separate scripts called content scripts, that can communicate with the rest of the add-on using a messaging API.

Learn more

Localization

In a XUL/XPCOM extension you handle localization by supplying DTD or properties for each supported language, and referring to them using locale statements inside the chrome.manifest. You can then include localized strings in UI elements or in code.

The general approach with WebExtensions is similar, but the details are all different. With WebExtensions you supply localized strings as a collection of JSON files, one for each locale.

To retrieve localized strings in add-on code, use the i18n API.

WebExtensions don't have direct support for localizing strings appearing in HTML, so you have to do this yourself, using JavaScript to retrieve localized strings and to replace the HTML with the localized version.

Learn more

Settings

XUL/XPCOM extensions typically store settings using the XPCOM preferences service or the inline options system.

With WebExtensions you write an HTML file that presents the settings UI, which can include a script for persisting the settings. The script gets access to all the WebExtensions APIs, and it's generally expected that you should use the storage API to persist settings.

You then assign the HTML file's URL to the options_ui key in manifest.json. Your settings page then appears in the add-on's entry in the Add-ons Manager.

Note that WebExtensions does not give you access to the Preferences API, so you can't directly get or set the browser's own preferences.

Learn more

Revision Source

<div>{{AddonSidebar}}</div>

<div class="summary">
<p>This article is a technical comparison between WebExtensions and "classic" extensions developed using direct XUL manipulation and direct access to XPCOM. It's intended to help orient people who maintain an add-on like this, and who are planning to port the add-on to WebExtensions.</p>

<p>This article covers both <a href="/en-US/Add-ons/Overlay_Extensions">overlay extensions</a> and <a href="/en-US/docs/Mozilla/Add-ons/Bootstrapped_extensions">bootstrapped extensions</a>, but not extensions developed using the Add-on SDK. For the Add-on SDK, please see <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Comparison_with_the_Add-on_SDK">Comparison with the Add-on SDK</a>.</p>
</div>

<p>At a very basic level, XUL/XPCOM extensions are similar to WebExtensions. They both include:</p>

<ul>
 <li>manifest files defining metadata for the add-on and some aspects of its behavior.</li>
 <li>JavaScript code that gets access to a set of privileged JavaScript APIs and that stays loaded for as long as the add-on itself is enabled.</li>
 <li>the ability to add specific UI elements, such as buttons, to the browser.</li>
</ul>

<p>Beyond that, though, the systems are very different. In particular:</p>

<ul>
 <li>Compared with XUL/XPCOM extensions, WebExtensions provide much more limited options for the add-on's UI, and a much more limited set of privileged JavaScript APIs.</li>
 <li>WebExtensions don't get direct access to web content (note, though, that this is also true of XUL/XPCOM extensions that expect to work with multiprocess Firefox).</li>
</ul>

<h2 id="Manifest">Manifest</h2>

<p>XUL/XPCOM extensions have two manifest files:</p>

<ul>
 <li>the <a href="/en-US/Add-ons/Install_Manifests">install.rdf</a> contains metadata about the extension such as its name, icons, and so on</li>
 <li>the <a href="/en-US/docs/Chrome_Registration">chrome.manifest</a>, that tells Firefox where it can find the components of the extension, including XUL overlays for the extension's interface, scripts for its behavior, and files containing localized strings.</li>
</ul>

<p>WebExtensions have a single manifest file called <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json">manifest.json</a>, that has a similar purpose. You use it to specify the add-on's name, description, icons, and so on, as well as to specify any buttons it adds to Firefox and to list scripts it needs to run. To get an overview of the components of a WebExtension, and how they are specified in manifest.json, see <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension">"Anatomy of a WebExtension"</a>.</p>

<h3>Learn more</h3>

<ul>
 <li><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json">manifest.json documentation</a></li>
 <li><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension">Anatomy of a WebExtension</a></li>
</ul>

<h2 id="UI">UI</h2>

<p>XUL/XPCOM extensions can build their UI by directly manipulating the XUL used to specify the browser's own UI. They do this either using overlays or, in the case of bootstrapped/restartless extensions, using JavaScript to modify the XUL document. They can not only add any elements to the browser's UI, they can also modify or remove existing elements. They can also use APIs like <a href="/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm">CustomizableUI.jsm</a> to build their UI.</p>

<p>WebExtensions don't get this kind of direct access. Instead, a combination of manifest.json keys and JavaScript APIs enable them to add a limited set of UI components to the browser. The available components are:</p>

<table class="fullwidth-table standard-table">
 <thead>
  <tr>
   <th scope="col" style="width: 20%;">Name</th>
   <th scope="col">Description</th>
   <th scope="col" style="width: 40%;">Specified using</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>Browser action</td>
   <td>Button in the browser toolbar, with an optional popup panel.</td>
   <td>
    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_action">browser_action</a></code> manifest key</p>

    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction">browserAction</a></code> API</p>
   </td>
  </tr>
  <tr>
   <td>Page action</td>
   <td>Button in the URL bar, with an optional popup panel.</td>
   <td>
    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/page_action">page_action</a></code> manifest key</p>

    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/pageAction">pageAction</a></code> API</p>
   </td>
  </tr>
  <tr>
   <td>Commands</td>
   <td>Keyboard shortcuts.</td>
   <td>
    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/commands">commands</a></code> manifest key</p>

    <p><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/commands">commands</a></code> API</p>
   </td>
  </tr>
  <tr>
   <td>Context menu</td>
   <td>Adds items and submenus to the browser's context menu.</td>
   <td><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/contextMenus">contextMenus</a></code> API</td>
  </tr>
 </tbody>
</table>

<h2 id="Privileged_APIs">Privileged APIs</h2>

<p>Both XUL/XPCOM extensions and WebExtensions can contain scripts that stay loaded for as long as the extension itself is enabled, and that have access to a set of privileged APIs. However, XUL/XPCOM extensions get access to a much wider range of APIs.</p>

<p>The scripts packaged with XUL/XPCOM extensions get access to the full set of <a href="/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface">XPCOM APIs</a> and <a href="/en-US/docs/Mozilla/JavaScript_code_modules">JavaScript code modules</a> through the <code><a href="/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components_object">Components</a></code> object. They also get direct access to the browser's internals through globals like <code><a href="/en-US/docs/Mozilla/Tech/XUL/tabbrowser">gBrowser</a></code>.</p>

<p>The equivalent WebExtension scripts are called <a href="/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">background scripts</a>, and they get access to a much smaller set of high-level JavaScript APIs. To see all the privileged APIs available to background scripts, see the <a href="/en-US/Add-ons/WebExtensions/API">summary API page</a>. Background scripts also get a <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window">window</a></code> global, with all the DOM objects that are available in a normal web page.</p>

<p>There are vastly more APIs available to XUL/XPCOM extensions than are available to WebExtensions, and for many XUL/XPCOM APIs, there isn't a WebExtensions substitute. The table below lists every API in the popular <a href="/en-US/docs/Mozilla/JavaScript_code_modules/Services.jsm">Services.jsm</a> module, describe what the equivalent WebExtensions API would be, if there is one.</p>

<table class="fullwidth-table standard-table">
 <thead>
  <tr>
   <th class="header" scope="col">Services.jsm API</th>
   <th class="header" scope="col">WebExtensions equivalent</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{ interface("nsIAndroidBridge") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsIXULAppInfo") }}<br />
    {{ interface("nsIXULRuntime") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsIAppShellService") }}</td>
   <td>None</td>
  </tr>
  <!--    <tr>
      <td><code>bookmarks</code></td>
      <td>{{interface("nsINavBookmarksService")}}</td>
      <td>Bookmarks service</td>
    </tr> -->
  <tr>
   <td>{{ interface("nsIBlocklistService") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsICacheService") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsICacheStorageService") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsIClipboard") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsIConsoleService") }}</td>
   <td><code><a href="/en-US/docs/Web/API/Console">window.console</a></code></td>
  </tr>
  <tr>
   <td>{{ interface("nsIContentPrefService") }}</td>
   <td>None</td>
  </tr>
  <tr>
   <td>{{ interface("nsICookieManager2") }}</td>
   <td><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies">cookies</a></code></td>
  </tr>
  <tr>
   <td>{{ interface("nsIMessageSender") }}</td>
   <td><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">Content scripts</a></td>
  </tr>
  <tr><!-- NEED INFO -->
   <td><a class="external" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/crashes/CrashManager.jsm">CrashManager.jsm</a></td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{ interface("nsIDirectoryService") }}<br />
    {{ interface("nsIProperties") }}</td>
   <td>Directory service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIDOMStorageManager") }}</td>
   <td>DOM Storage Manager</td>
  </tr>
  <tr>
   <td>{{ interface("nsIDOMRequestService") }}</td>
   <td>DOMRequest service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIDownloadManager") }}</td>
   <td>Download manager</td>
  </tr>
  <tr>
   <td>{{ interface("nsIDroppedLinkHandler") }}</td>
   <td>Dropped link handler service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIEventListenerService") }}</td>
   <td>Event listener service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIEffectiveTLDService") }}</td>
   <td>EffectiveTLD service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIFocusManager") }}</td>
   <td>Focus manager</td>
  </tr>
  <tr>
   <td>{{ interface("nsIIOService") }}<br />
    {{ interface("nsIIOService2") }}</td>
   <td>I/O Service</td>
  </tr>
  <tr>
   <td>{{ interface("nsILocaleService") }}</td>
   <td>Locale service</td>
  </tr>
  <tr>
   <td>{{ interface("nsILoginManager") }}</td>
   <td>Password Manager service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIWinMetroUtils") }}</td>
   <td><sup><a href="#note2">2</a></sup></td>
  </tr>
  <tr>
   <td>{{ interface("nsIMessageBroadcaster") }}<br />
    {{ interface("nsIFrameScriptLoader") }}</td>
   <td><a href="/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Message_manager_overview#Global_frame_message_manager">Global frame message manager</a><sup><a href="#note3">3</a></sup></td>
  </tr>
  <tr>
   <td>{{ interface("nsIObserverService") }}</td>
   <td>Observer service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIPermissionManager") }}</td>
   <td>Permission manager service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIMessageBroadcaster") }}<br />
    {{ interface("nsIProcessScriptLoader") }}</td>
   <td><a href="/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Message_manager_overview#Global_parent_process_message_manager">Global parent process message manager</a><sup><a href="#note3">3</a></sup></td>
  </tr>
  <tr>
   <td>{{ interface("nsIPrefBranch") }}<br />
    {{ interface("nsIPrefBranch2") }}<br />
    {{ interface("nsIPrefService") }}</td>
   <td>Preferences service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIPromptService") }}</td>
   <td>Prompt service</td>
  </tr>
  <tr>
   <td>{{ interface("mozIJSSubScriptLoader") }}</td>
   <td>JavaScript subscript loader service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIScriptSecurityManager") }}</td>
   <td>Script security manager</td>
  </tr>
  <tr>
   <td>{{ interface("nsIBrowserSearchService") }}</td>
   <td>Browser search service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIAppStartup") }}</td>
   <td>Application startup service</td>
  </tr>
  <tr>
   <td>{{ interface("mozIStorageService") }}</td>
   <td><a href="/en-US/Storage" title="en-US/Storage">Storage API</a> service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIStringBundleService") }}</td>
   <td>String bundle service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIPropertyBag2") }}</td>
   <td>System info service</td>
  </tr>
  <tr>
   <td>{{ interface("nsITelemetry") }}</td>
   <td>Telemetry service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIThreadManager") }}</td>
   <td><a href="/en-US/The_Thread_Manager" title="en-US/The Thread Manager">Thread Manager</a> service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIURIFixup") }}</td>
   <td>URI Fixup service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIURLFormatter") }}</td>
   <td>URL Formatter service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIVersionComparator") }}</td>
   <td>Version comparator service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIWindowMediator") }}</td>
   <td>Window mediator service</td>
  </tr>
  <tr>
   <td>{{ interface("nsIWindowWatcher") }}</td>
   <td>Window watcher service</td>
  </tr>
 </tbody>
</table>

<h3>Learn more</h3>

<ul>
 <li><a href="/en-US/Add-ons/WebExtensions/API">JavaScript APIs available to WebExtensions</a></li>
 <li><a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">Background scripts in WebExtensions</a></li>
</ul>

<h2 id="Interacting_with_web_content">Interacting with web content</h2>

<p>Historically, XUL/XPCOM extensions have been able to get direct access to web content. For example, they can directly access and modify the page DOM using <code><a href="/en-US/docs/Mozilla/Tech/XUL/tabbrowser">gBrowser</a></code>:</p>

<pre class="brush: js">
gBrowser.contentWindow.document.querySelector("h1").innerHTML = "yadda yadda";</pre>

<p>However, this is only possible in single-process Firefox. In <a href="/en-US/docs/Mozilla/Firefox/Multiprocess_Firefox">multiprocess Firefox</a>, web content and add-on code run in different processes, so this direct access is no longer possible, and extensions which rely on it will break. Multiprocess Firefox is coming soon, and multiprocess compatibility will be a necessity.</p>

<p>XUL/XPCOM extensions can still interact with web content in multiprocess Firefox by <a href="/en-US/Add-ons/Working_with_multiprocess_Firefox">refactoring the code that accesses web content into separate scripts called frame scripts, and using the message manager to communicate with these scripts</a>. But this is complex and can involve deep changes to the extension's code.</p>

<p>WebExtensions are multiprocess-compatible by default: code that interacts with web content is factored into separate scripts called <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">content scripts</a>, that can communicate with the rest of the add-on using a messaging API.</p>

<h3>Learn more</h3>

<ul>
 <li><a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts">Content scripts in WebExtensions</a></li>
</ul>

<h2 id="i18n">Localization</h2>

<p>In a XUL/XPCOM extension you handle localization by supplying DTD or properties for each supported language, and referring to them using locale statements inside the chrome.manifest. You can then include localized strings in UI elements or in code.</p>

<p>The general approach with WebExtensions is similar, but the details are all different. With WebExtensions you supply localized strings as a collection of JSON files, one for each locale.</p>

<p>To retrieve localized strings in add-on code, use the <code><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/i18n">i18n</a></code> API.</p>

<p>WebExtensions don't have direct support for localizing strings appearing in HTML, so you have to do this yourself, using JavaScript to retrieve localized strings and to replace the HTML with the localized version.</p>

<h3>Learn more</h3>

<ul>
 <li><a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Internationalization">WebExtensions Internationalization guide.</a></li>
 <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n">Example internationalized WebExtension.</a></li>
</ul>

<h2 id="Settings">Settings</h2>

<p>XUL/XPCOM extensions typically store settings using the <a href="/en-US/Add-ons/Code_snippets/Preferences">XPCOM preferences service</a> or the <a href="/en-US/docs/Mozilla/Add-ons/Inline_Options">inline options</a> system.</p>

<p>With WebExtensions you write an HTML file that presents the settings UI, which can include a script for persisting the settings. The script gets access to all the WebExtensions APIs, and it's generally expected that you should use the <code><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage">storage</a></code> API to persist settings.</p>

<p>You then assign the HTML file's URL to the <code><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/options_ui">options_ui</a></code> key in manifest.json. Your settings page then appears in the add-on's entry in the Add-ons Manager.</p>

<p>Note that WebExtensions does not give you access to the <a href="/en-US/docs/Mozilla/Tech/Preferences_API">Preferences API</a>, so you can't directly get or set the browser's own preferences.</p>

<h3 id="Learn_more_3">Learn more</h3>

<ul>
 <li><a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Options_pages">Introduction to options pages</a></li>
 <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/favourite-colour">An example add-on that has an options page</a></li>
</ul>
Revert to this revision