Popup and storage
Build the popup interface
Create a small accessible form whose markup and scripts are packaged with the extension instead of loaded remotely.
The popup is a regular HTML page shipped inside the extension. It can use CSS, ES modules, and every extension API the manifest allows. The one thing to keep in mind: it disappears the moment focus moves somewhere else.
Let’s build the Page Notes popup. It needs a label, a textarea, a save button, a place for status messages, and a script.
<form id="note-form">
<label for="note">Note for this page</label>
<textarea id="note" name="note"></textarea>
<button>Save note</button>
<p id="status" role="status"></p>
</form>
<script type="module" src="popup.js"></script>
The role="status" on the paragraph makes screen readers announce the text when it changes. The script is an ES module, loaded from a file next to popup.html.
No remote code, no inline code
Manifest V3 requires all executable code to be packaged with the extension. You can’t load a script from a CDN. You can’t write <script> tags with code inside them. You can’t use onclick="..." attributes.
Extension pages also ship with a strict content security policy, a set of rules the browser enforces about which code may run. Inline scripts are blocked by it. So everything goes in popup.js, and we attach listeners from there:
const form = document.getElementById('note-form')
const status = document.getElementById('status')
form.addEventListener('submit', event => {
event.preventDefault()
status.textContent = 'Saving...'
})
There’s a nice side effect. The code the store reviewers read is the exact code users run. Nothing can change after publication.
Closing is normal
Users close popups all the time, often by accident. Treat that as the expected case.
The popup can vanish while an asynchronous write is still in flight. So we save right away from the submit event, and we treat the storage write as the source of truth, not a variable in the popup. If the only copy of the draft lives in popup.js, it’s already lost.
Size and keyboard
Give the popup a fixed width, around 320 pixels, and a font size you can actually read. Then test it without the mouse. Tab to the textarea, type, tab to the button, press Enter. If anything on that path is unreachable, fix it now while the form is small.
One more test. Open the popup, type something, click outside without saving, and open it again. The text is gone. Decide now what you want to happen: discard the draft, save it automatically, or restore it. Any of the three is fine. What’s not fine is leaving it to chance. Make the interface say what it does.
Lesson completed