DEV Community

Alexander Burnett
Alexander Burnett

Posted on

A settings page for a Manifest V3 extension with chrome.storage.sync (and no framework)

When I built the options page for Promo Drop, I wanted three toggles, instant saves, and settings that follow the user to every Chrome they sign in to. No React, no build step. Here is the whole pattern.

1. Declare the page in the manifest

"options_ui": { "page": "options.html", "open_in_tab": true },
"permissions": ["storage"]
Enter fullscreen mode Exit fullscreen mode

storage is the only permission this page needs.

2. One source of defaults

const DEFAULTS = { showPanel: true, showCashback: true, compactMode: false };
Enter fullscreen mode Exit fullscreen mode

Keep this in one place and pass it to every get call, so a first-time user never sees undefined.

3. Load the saved values

document.addEventListener('DOMContentLoaded', async () => {
  const settings = await chrome.storage.sync.get(DEFAULTS);
  for (const [key, value] of Object.entries(settings)) {
    const box = document.getElementById(key);
    if (box) box.checked = value;
  }
});
Enter fullscreen mode Exit fullscreen mode

Passing the defaults object as the key means Chrome fills in anything missing for you.

4. Save on change, not on a Save button

document.addEventListener('change', (e) => {
  if (e.target.matches('input[type="checkbox"]')) {
    chrome.storage.sync.set({ [e.target.id]: e.target.checked });
  }
});
Enter fullscreen mode Exit fullscreen mode

One listener covers every toggle, and users never lose a change because they forgot to click Save.

5. React to changes everywhere else

chrome.storage.onChanged.addListener((changes, area) => {
  if (area === 'sync' && changes.showPanel) {
    togglePanel(changes.showPanel.newValue);
  }
});
Enter fullscreen mode Exit fullscreen mode

Your content script updates live, in every open tab, the moment the user flips a switch.

Things that caught me out

  • storage.sync has quotas (about 100 KB total and 8 KB per item). Settings fit easily; anything bigger belongs in storage.local.
  • The sync write rate is limited, so never call set inside a slider's input event. Use change.
  • Test with a second Chrome profile signed in to the same account to watch sync happen.

That is the entire options page: one HTML file, about 30 lines of JavaScript, and nothing to build. The extension it belongs to lists tested Whop promo codes; you can see it at promodrop.codes.

Top comments (0)