Briefly
This is an object stored in window
that allows you to persistently save data in the browser. It works as a key-value data storage — when saving data, we specify the field name where the data should be saved and then use this name to retrieve it.
Values are stored as strings. When attempting to save other types of data, they will be converted to a string. For example, if you write a number, then when reading it back, you will get the number stored as a string.
There are no time storage limitations, but it can be cleared manually by the user or automatically by the browser when full (WebKit-based browsers, like Safari, clear local
if it hasn't been accessed for 7 days).
The maximum data size is limited to 5MB.
Example
Storing data:
window.localStorage.setItem('name', 'WebGuide Dog')
window.localStorage.setItem('name', 'WebGuide Dog')
When reading previously stored data by the key name
, we get WebGuide
:
const name = window.localStorage.getItem('name')console.log(name)// 'WebGuide Dog'
const name = window.localStorage.getItem('name') console.log(name) // 'WebGuide Dog'
Re-writing with the same key will replace the data:
window.localStorage.setItem('name', 'Dog WebGuide')const name = window.localStorage.getItem('name')console.log(name)// 'Dog WebGuide'
window.localStorage.setItem('name', 'Dog WebGuide') const name = window.localStorage.getItem('name') console.log(name) // 'Dog WebGuide'
How to understand
If you need to store data in the browser for a long time and the volume of this data is large enough, then local
is what you need. The data will be stored indefinitely and can only be deleted in two cases: when exceeding the data size limit or when the storage is cleared by the user or programmatically.
How to write
Writing
To write, use the method set
. It takes two string parameters: the key under which the value will be saved and the value itself.
window.localStorage.setItem('name', 'WebGuide Dog')
window.localStorage.setItem('name', 'WebGuide Dog')
Reading
Reading is done with get
, which has one parameter that specifies the key for reading and returns the retrieved value from the storage. If there is no value for this key, the method will return null
.
window.localStorage.getItem('name') // will return 'WebGuide Dog'window.localStorage.getItem('user') // will return `null`
window.localStorage.getItem('name') // will return 'WebGuide Dog' window.localStorage.getItem('user') // will return `null`
Deleting
Removes the entry from the storage remove
. It will succeed even if the specified key does not exist in the storage.
window.localStorage.removeItem('name')window.localStorage.removeItem('user')
window.localStorage.removeItem('name') window.localStorage.removeItem('user')
Clearing the storage
The method clear
clears the storage completely.
window.localStorage.clear()
window.localStorage.clear()
Number of fields in the storage
Using the length
property, you can find out how many fields have been recorded in the storage.
console.log(window.localStorage.length)// 0
console.log(window.localStorage.length) // 0
Getting the key by index
The method key
gets the key by index. Values in the storage are stored in the order they were added, so the value added first will be at position 0
and so on.
window.localStorage.setItem('name', 'WebGuide Dog')console.log(window.localStorage.key(0))// 'name'
window.localStorage.setItem('name', 'WebGuide Dog') console.log(window.localStorage.key(0)) // 'name'
Thus, by using the number of fields in the storage and getting the key by index, you can organize the iteration over all values in the storage.
const localStorageSize = window.localStorage.lengthfor (let i = 0; i < localStorageSize; i++) { console.log( window.localStorage.getItem(localStorage.key(i)) )}
const localStorageSize = window.localStorage.length for (let i = 0; i < localStorageSize; i++) { console.log( window.localStorage.getItem(localStorage.key(i)) ) }
Events
When setting a value in the storage, a global storage
event is triggered, which can be used to track changes in the storage.
💡 The event occurs only on other open pages of the current site.
The event contains properties:
key
— the key that was changed (when theclear
method is called, the key will be( ) null
);old
— the old value recorded in the field;Value new
— the new value recorded in the field;Value url
— the address of the page where the change was made.
window.addEventListener('storage', function (evt) { console.log(evt)})
window.addEventListener('storage', function (evt) { console.log(evt) })
In practice
Advice 1
🛠 Using local
, you can save data related to the user without storing it on the server. In the following example, we will remember the font size on the website and restore the size from storage if it was changed beforehand.
🛠 It can be used to synchronize multiple tabs open in the browser. When the font size is changed in one tab, we learn about it in all the others and change the size as well.
function changePageFontSize(size) { document.style.fontSize = `${size}px`}window.addEventListener('storage', function (evt) { if (evt.key === 'pageFontSize') { changePageFontSize(evt.newValue) }})
function changePageFontSize(size) { document.style.fontSize = `${size}px` } window.addEventListener('storage', function (evt) { if (evt.key === 'pageFontSize') { changePageFontSize(evt.newValue) } })
🛠 Sometimes we need to save not just text but a whole data structure. This is where JSON
comes in handy.
const user = { name: 'WebGuide Dog', avatarUrl: 'mascot-doka.svg'}localStorage.setItem('user', JSON.stringify(user))
const user = { name: 'WebGuide Dog', avatarUrl: 'mascot-doka.svg' } localStorage.setItem('user', JSON.stringify(user))
And after reading we parse:
function readUser() { const userJSON = localStorage.getItem('user') if (userJSON === null) { return undefined } // If for some reason the storage contains an invalid JSON, // we protect ourselves from this try { return JSON.parse(userJSON) } catch (e) { localStorage.removeItem('user') return undefined }}console.log(readUser())// {// name: 'WebGuide Dog',// avatarUrl: 'mascot-doka.svg'// }
function readUser() { const userJSON = localStorage.getItem('user') if (userJSON === null) { return undefined } // If for some reason the storage contains an invalid JSON, // we protect ourselves from this try { return JSON.parse(userJSON) } catch (e) { localStorage.removeItem('user') return undefined } } console.log(readUser()) // { // name: 'WebGuide Dog', // avatarUrl: 'mascot-doka.svg' // }
🛠 If your site uses analytics scripts or other external libraries, they will also have access to the storage. Therefore, it's better to name the keys for storing with a prefix in a consistent style. For example, when writing anything on such a site, I would choose the prefix YD
, so that only the necessary values can be grouped or filtered in the developer tools.
🛠 Use wrapper functions to prevent errors related to failed write attempts, the absence of local
in the browser, and code duplication.
function getItem(key, value) { try { return window.localStorage.getItem(key) } catch (e) { console.log(e) }}function setItem(key, value) { try { return window.localStorage.setItem(key, value) } catch (e) { console.log(e) }}function setJSON(key, value) { try { const json = JSON.stringify(value) setItem(key, json) } catch (e) { console.error(e) }}function getJSON(key) { try { const json = getItem(key) return JSON.parse(json) } catch (e) { console.error(e) }}
function getItem(key, value) { try { return window.localStorage.getItem(key) } catch (e) { console.log(e) } } function setItem(key, value) { try { return window.localStorage.setItem(key, value) } catch (e) { console.log(e) } } function setJSON(key, value) { try { const json = JSON.stringify(value) setItem(key, json) } catch (e) { console.error(e) } } function getJSON(key) { try { const json = getItem(key) return JSON.parse(json) } catch (e) { console.error(e) } }
Advice 2
🛠 How to prevent data deletion from storage?When and how does data deletion occur? How can we retain data?You can use two methods of data storage - "temporary" and "permanent." In "temporary" mode, the browser can delete your data, provided that this process does not interfere with the user's experience. In permanent mode, this will not happen, even in case of low storage space. However, users can independently clear the storage in this mode.By default, all storage (`localStorage`, `IndexedDB`, `Cache API`, etc.) operates in temporary mode. If the site did not [request permanent data storage](https://web.dev/persistent-storage/) — the browser can delete its data at its discretion. For example, if there is little space on the device.🛠 What does the cleanup process look like?During automatic cleanup, browsers should delete the least valuable data for the user.Chromium-based browsers free up space sequentially by deleting data from sites. Deletion starts with sites that have not been visited for a long time and continues until enough space is freed.Internet Explorer 10+ does not clear data but does not allow data to be written beyond the limit.Firefox starts clearing when the free disk space runs out. The order of deletion is determined by the same principle as in Chromium-based browsers.Safari used to never delete data, but now uses a [seven-day limit on storing all recorded data](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/).🛠 How to enable permanent data storage mode?All the necessary methods for working with browser storage are found in `window.navigator.storage`. The method we need is called `persist()`:```js(async () => { // Attempts to switch to "permanent" storage mode. // Returns true if successful, false if not. const persistModeEnabled = await window.navigator.storage?.persist()})()
🛠 How to prevent data deletion from storage? When and how does data deletion occur? How can we retain data? You can use two methods of data storage - "temporary" and "permanent." In "temporary" mode, the browser can delete your data, provided that this process does not interfere with the user's experience. In permanent mode, this will not happen, even in case of low storage space. However, users can independently clear the storage in this mode. By default, all storage (`localStorage`, `IndexedDB`, `Cache API`, etc.) operates in temporary mode. If the site did not [request permanent data storage](https://web.dev/persistent-storage/) — the browser can delete its data at its discretion. For example, if there is little space on the device. 🛠 What does the cleanup process look like? During automatic cleanup, browsers should delete the least valuable data for the user. Chromium-based browsers free up space sequentially by deleting data from sites. Deletion starts with sites that have not been visited for a long time and continues until enough space is freed. Internet Explorer 10+ does not clear data but does not allow data to be written beyond the limit. Firefox starts clearing when the free disk space runs out. The order of deletion is determined by the same principle as in Chromium-based browsers. Safari used to never delete data, but now uses a [seven-day limit on storing all recorded data](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/). 🛠 How to enable permanent data storage mode? All the necessary methods for working with browser storage are found in `window.navigator.storage`. The method we need is called `persist()`: ```js (async () => { // Attempts to switch to "permanent" storage mode. // Returns true if successful, false if not. const persistModeEnabled = await window.navigator.storage?.persist() })()
We can enhance our code by using the persisted
method. This method will return true
if the storage has already been switched to permanent mode.
We call the persisted
method and switch the storage to permanent mode only if it has not been switched yet:
(async () => { // boolean value indicating whether // the "permanent" data storage mode is enabled initially const isAlreadyPersist = await window.navigator.storage?.persisted() if (isAlreadyPersist) { console.info('The storage has already been switched to permanent storage mode.') return } // boolean value indicating whether // it was possible to switch to "permanent" storage mode const persistModeEnabled = await window.navigator.storage?.persist() if (persistModeEnabled) { console.info('The browser successfully changed the storage mode to "permanent".') return } console.info( 'The browser encountered issues when trying to change the mode. You may want to update to the latest version or use HTTPS protocol on the site.' )})()
(async () => { // boolean value indicating whether // the "permanent" data storage mode is enabled initially const isAlreadyPersist = await window.navigator.storage?.persisted() if (isAlreadyPersist) { console.info('The storage has already been switched to permanent storage mode.') return } // boolean value indicating whether // it was possible to switch to "permanent" storage mode const persistModeEnabled = await window.navigator.storage?.persist() if (persistModeEnabled) { console.info('The browser successfully changed the storage mode to "permanent".') return } console.info( 'The browser encountered issues when trying to change the mode. You may want to update to the latest version or use HTTPS protocol on the site.' ) })()