Sebastian Gomez
The Options Page in Chrome Extensions
Just as extensions let users customize the Chrome browser, the options page lets users customize the extension itself. Use the options page to enable features and let users choose which capabilities are relevant to their needs.
Accessing the options page
Users can reach the options page through a direct link, or by right clicking the extension icon in the toolbar and selecting "Options". They can also navigate to it by opening chrome://extensions, locating the desired extension, clicking "Details", and selecting the options link. Next, I'll show you how to create and configure an options page.
Create the options.html file
In your project folder, create a file named options.html and add the following code:
<!DOCTYPE html>
<html>
<head>
<title>Mi color favorito</title>
</head>
<body>
<select id="color">
<option value="red">rojo</option>
<option value="green">verde</option>
<option value="blue">azul</option>
<option value="yellow">amarillo</option>
</select>
<label>
<input type="checkbox" id="like" />
Me gustan los colores
</label>
<div id="status"></div>
<button id="save">Guardar</button>
<script src="options.js"></script>
</body>
</html>Update the Manifest
Open your manifest.json file and add the reference to the options page:
{
"manifest_version": 3,
"name": "Mi Extensión",
"version": "0.0.1",
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icon-16.png",
"48": "icon-48.png",
"128": "icon-128.png"
}
},
"options_page": "options.html"
}CSS and JavaScript
Just like popup.html, the options page lets you use HTML, CSS, and JavaScript. Keep in mind that the options page has no direct link to the popup or to other parts of the application, so interaction with it is limited and we can only communicate through Chrome storage. For example, let's add JavaScript in options.js so the color chosen by the user gets saved.
Since Chrome 88, the chrome.storage APIs return Promises, so we can write them with async/await, which is the idiomatic style today. Here is the modernized options.js:
// Save the options to chrome.storage
const saveOptions = async () => {
// Read the selected color value and the checkbox state
const color = document.getElementById('color').value;
const likesColor = document.getElementById('like').checked;
// Save the values to chrome.storage.sync
await chrome.storage.sync.set({ favoriteColor: color, likesColor });
// Update the status to let the user know the options were saved
const status = document.getElementById('status');
status.textContent = 'Opciones guardadas.';
setTimeout(() => {
status.textContent = '';
}, 750);
};
// Restore the select and checkbox state using the preferences
// stored in chrome.storage
const restoreOptions = async () => {
const items = await chrome.storage.sync.get({ favoriteColor: 'red', likesColor: true });
// Set the retrieved values on the form elements
document.getElementById('color').value = items.favoriteColor;
document.getElementById('like').checked = items.likesColor;
};
// Restore the options when the document content has loaded
document.addEventListener('DOMContentLoaded', restoreOptions);
// Save the options when the save button is clicked
document.getElementById('save').addEventListener('click', saveOptions);Note: if you prefer to keep compatibility with older code, these same APIs also accept a callback as their last argument, for example chrome.storage.sync.get({ favoriteColor: 'red' }, (items) => {... }). It works, but the async/await form is cleaner and is the recommended approach today.
Before using storage you must add the corresponding permission in your manifest.json:
"permissions": [
"storage"
]Note on permissions: if you've been following this series, you may already have activeTab and scripting in your permissions list from earlier chapters. For this chapter's options page the only permission you need is storage; the other two are not used by the code we see here.
How to declare the options page behavior in Chrome extensions
When developing a Chrome extension, it's essential to define how the configuration options will be presented to the user. There are two main types of options pages for extensions: full page and embedded. The type is determined by how you declare it in the manifest.json file.
Full page options
Full page options open in a new browser tab. This approach is useful if your extension needs a larger interface for complex configurations. To register a full page options page, you include the corresponding HTML file in the options_page field of the manifest.
Example in the manifest.json file:
{
"name": "Mi extensión",
"options_page": "options.html"
}When the user opens the extension's options, a new tab opens showing the content of options.html.
Embedded options
Embedded options let users adjust the extension's settings without leaving Chrome's extensions management page. This type of options page appears inside an embedded box on that same page. To declare embedded options, register the HTML file in the options_ui field of the extension manifest and set the open_in_tab key to false.
Example in the manifest.json file:
{
"name": "Mi extensión",
"options_ui": {
"page": "options.html",
"open_in_tab": false
}
}With this setup, users can access and adjust the extension's options directly from Chrome's extensions management page, without needing to open a new tab.
Using the saved options from the popup
Communication from our main popup works in a similar way, using the Storage API to fetch the data and apply it as needed. For example, in our case we can change the backgroundColor of the .login-container element to the color the user chose in the options. Let's modify the popup.js file to do this:
const restoreOptions = async () => {
const items = await chrome.storage.sync.get({ favoriteColor: 'red', likesColor: true });
document.querySelector('.login-container').style.backgroundColor = items.favoriteColor;
};
document.addEventListener('DOMContentLoaded', restoreOptions);Notice that here we read storage with the same pattern as in options.js: we pass an object with default values to chrome.storage.sync.get and use await. That way, both the options page and the popup share exactly the same way of reading and recoloring, without mixing styles.
Linking to the options page
An extension can link directly to its options page by calling chrome.runtime.openOptionsPage(). For example, you can add a button in the popup to take the user to the options page.
Code in popup.html:
<button id="go-to-options">Ir a opciones</button>
<script src="popup.js"></script>Code in popup.js:
document.querySelector('#go-to-options').addEventListener('click', () => {
chrome.runtime.openOptionsPage();
});Note: chrome.runtime.openOptionsPage() has existed since Chrome 42, so it's always available in any Manifest V3 capable browser. That's why you no longer need the old window.open(chrome.runtime.getURL('options.html')) fallback: it was defensive code that never actually ran.
If you want to combine both pieces, recoloring the container when the popup opens and opening the options from the button, just merge them inside the same popup.js:
document.addEventListener('DOMContentLoaded', async () => {
// Recolor the container based on the saved configuration
const items = await chrome.storage.sync.get({ favoriteColor: 'red', likesColor: true });
document.querySelector('.login-container').style.backgroundColor = items.favoriteColor;
// Open the options page from the button
document.querySelector('#go-to-options').addEventListener('click', () => {
chrome.runtime.openOptionsPage();
});
});This code makes sure the container background changes to the user's preferred color, stored in chrome.storage, and provides a direct link to the options page from the popup.
Suggested exercises
- Add a third control to
options.html(for example, a text field for a username), save it tochrome.storage.sync, and read it from the popup. - Convert your extension to embedded options using
options_uiwithopen_in_tab: falseand compare the experience with the full page one. - Replace the default values passed to each
getwith a shared defaults constant and reuse it in bothoptions.jsandpopup.js.
3-point summary
- The options page lets you customize your extension and only communicates with the rest of the app through
chrome.storage. - You can declare it as a full page (
options_page) or embedded (options_uiwithopen_in_tab: false), depending on how complex your configuration is. - Since Chrome 88 the storage APIs return Promises, so use
async/awaitand a single read pattern in both the options and the popup.
I hope you found this guide useful and that you can apply it to a project you have in mind. Don't forget to leave a comment if it helped, subscribe for more content, and share the post using the social links below. Good luck and keep building.
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.