Popup and storage

Load and render safely

Initialize asynchronous popup state without racing user input and render stored text without interpreting it as HTML.

8 minute lesson

~~~

Storage reads are asynchronous. The user can interact before an unfinished initialization unless the interface has an explicit loading state.

Disable the form while resolving the tab and stored note, then enable it. Assign note text through .value or .textContent, never innerHTML, because stored content is still untrusted data.

form.hidden = true
const result = await chrome.storage.local.get(key)
note.value = result[key] ?? ''
form.hidden = false
note.focus()

Hiding the entire form removes context and can cause layout movement. A visible disabled form or stable skeleton can communicate what is loading while preserving its eventual space. On failure, keep a retry or close path; do not enable save when the page key is unknown.

Initialization also has a race with typing. If the form becomes editable before the read finishes, a late storage result can overwrite the user’s input. Use one explicit state transition from loading to ready, or ignore a late result after the user has edited. Keep status text separate from the note value.

Add loading, ready, saved, unavailable, and error states. Slow the storage read, try to type during it, and test a stored note containing <img onerror=alert(1)>. The string must appear literally, with no network request or DOM element created from it.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →