Popup and storage
Load and render safely
Initialize asynchronous popup state without racing user input and render stored text without interpreting it as HTML.
When the popup opens, it has to find the active tab and read the stored note before it can show anything. Both steps are asynchronous. In the meantime the user is already there, and they can start typing into a form that isn’t ready.
We need an explicit loading state.
Load, then enable
The simplest version hides the form until the note is loaded:
form.hidden = true
const result = await chrome.storage.local.get(key)
note.value = result[key] ?? ''
form.hidden = false
note.focus()
storage.local.get(key) returns an object, so we pick the property out of it. If there’s no note yet we fall back to an empty string.
Hiding the whole form works, but it’s a bit crude. The popup opens empty, then jumps when the form appears. A better version keeps the form visible but disabled, so the layout doesn’t move and the user sees what’s coming. Either way, the rule is the same: one clear transition from loading to ready.
If loading fails, don’t enable the save button. A note saved under an unknown key is a note nobody will ever find again. Show the error and a way to retry or close.
The typing race
Here’s a subtle bug. Say the form is enabled from the start. The user types “call Marco”. Then the storage read completes and sets note.value to last week’s note. The user’s text is gone.
Two fixes work. Keep the form disabled until the read finishes, which is what the code above does. Or, if you want the form editable immediately, ignore the storage result when the user has already edited. Pick one. Don’t leave both paths open.
Keep the status message in its own element too. Never write “Saved” into the textarea.
Never innerHTML
Stored note text is still untrusted data. It came from a textarea, and someone could have pasted anything in there. Render it with .value on the textarea or .textContent on any other element. Never with innerHTML.
Test this directly. Save a note that contains <img onerror=alert(1)>. Reopen the popup. You must see that exact string as text, no alert, no broken image, and nothing in the Network panel.
Now give the popup its full set of states: loading, ready, saved, unavailable, and error. Slow down the storage read with a setTimeout and try to type during it. Try a restricted page for the unavailable state. Each state should be visible and each transition deliberate.
Lesson completed