| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: Local Storage API | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | pagination_prev: demos/data/index | 
					
						
							|  |  |  | pagination_next: demos/cloud/index | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | sidebar_custom_props: | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  |   summary: Reading and writing data in an in-browser Key-Value store | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The Storage API, encompassing `localStorage` and `sessionStorage`, describes | 
					
						
							|  |  |  | simple key-value stores that only support string values and keys. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | This demo covers two common use patterns: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - "Row Objects" shows a simple convention for loading and storing row objects | 
					
						
							|  |  |  | - "Simple Strings" discusses how to persist and recover a raw Storage | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-30 07:10:37 +00:00
										 |  |  | :::note Tested Deployments | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Each browser demo was tested in the following environments: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | Browser     | Date       | | 
					
						
							|  |  |  | |:------------|:-----------| | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | | Chrome 131  | 2024-12-23 | | 
					
						
							|  |  |  | | Safari 18.2 | 2024-12-31 | | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | ## Row Objects
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Consider the following array of objects of data: | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | [ | 
					
						
							|  |  |  |   { Name: "Barack Obama", Index: 44 }, | 
					
						
							|  |  |  |   { Name: "Donald Trump", Index: 45 }, | 
					
						
							|  |  |  |   { Name: "Joseph Biden", Index: 46 } | 
					
						
							|  |  |  | ] | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 04:47:57 +00:00
										 |  |  | Storage API expects values to be strings. The simplest approach is to generate | 
					
						
							|  |  |  | strings using `JSON.stringify` and store using the row index as a key: | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | | Key | Value                                | | 
					
						
							|  |  |  | |:---:|:-------------------------------------| | 
					
						
							|  |  |  | |  0  | `{"Name":"Barack Obama","Index":44}` | | 
					
						
							|  |  |  | |  1  | `{"Name":"Donald Trump","Index":45}` | | 
					
						
							|  |  |  | |  2  | `{"Name":"Joseph Biden","Index":46}` | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Importing Data
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | Starting from a worksheet, the SheetJS `sheet_to_json` method[^1] generates an | 
					
						
							|  |  |  | array of row objects. `localStorage.setItem` will store data in Local Storage: | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | function sheet_to_localStorage(worksheet) { | 
					
						
							|  |  |  |   const aoo = XLSX.utils.sheet_to_json(worksheet); | 
					
						
							|  |  |  |   for(let i = 0; i < aoo.length; ++i) { | 
					
						
							|  |  |  |     localStorage.setItem(i, JSON.stringify(aoo[i])); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | #### Exporting Data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `localStorage.length` returns the total number of entries. A simple `for` loop | 
					
						
							|  |  |  | can cover the keys (integers from `0` to `localStorage.length - 1` inclusive) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | `localStorage.getItem` will load the stringified data from the Local Storage. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following function collects data from `localStorage` to an array of strings: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function localStorage_to_array_of_strings() { | 
					
						
							|  |  |  |   const strings = []; | 
					
						
							|  |  |  |   for(let i = 0; i < localStorage.length; ++i) { | 
					
						
							|  |  |  |     aoo.push(localStorage.getItem(i)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return strings; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Since each entry is a string created using `JSON.stringify`, an object can be | 
					
						
							|  |  |  | constructed using `JSON.parse`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function localStorage_to_array_of_objects() { | 
					
						
							|  |  |  |   const objects = []; | 
					
						
							|  |  |  |   for(let i = 0; i < localStorage.length; ++i) { | 
					
						
							|  |  |  |     aoo.push(JSON.parse(localStorage.getItem(i))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return objects; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `json_to_sheet`[^2] method will create a new worksheet from the | 
					
						
							|  |  |  | array of objects: | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function localStorage_to_sheet() { | 
					
						
							|  |  |  |   const aoo = []; | 
					
						
							|  |  |  |   for(let i = 0; i < localStorage.length; ++i) { | 
					
						
							|  |  |  |     aoo.push(JSON.parse(localStorage.getItem(i))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return XLSX.utils.json_to_sheet(aoo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Live Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 04:16:13 +00:00
										 |  |  | This demo will fetch https://docs.sheetjs.com/pres.numbers, fill `localStorage` | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | with rows, then generate a worksheet from the rows and write to a new file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | After saving the exported file, the Local Storage can be inspected in the | 
					
						
							|  |  |  | "Local Storage" section of the "Application" Tab of Developer Tools: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | :::caution pass | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This example is for illustration purposes. If array of objects is available, it | 
					
						
							|  |  |  | is strongly recommended to convert that array to a worksheet directly. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Live Demo</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJStorage() { | 
					
						
							| 
									
										
										
										
											2024-04-26 04:16:13 +00:00
										 |  |  |   const [url, setUrl] = React.useState("https://docs.sheetjs.com/pres.numbers"); | 
					
						
							| 
									
										
										
										
											2023-07-21 09:17:32 +00:00
										 |  |  |   const set_url = (evt) => setUrl(evt.target.value); | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  |   const [out, setOut] = React.useState(""); | 
					
						
							|  |  |  |   const xport = React.useCallback(async() => { | 
					
						
							|  |  |  |     // get first worksheet data as array of objects | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  |     const wb = XLSX.read(await (await fetch(url)).arrayBuffer()); | 
					
						
							|  |  |  |     const aoo = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // reset and populate localStorage | 
					
						
							|  |  |  |     localStorage.clear(); | 
					
						
							|  |  |  |     for(var i = 0; i < aoo.length; ++i) localStorage.setItem(i, JSON.stringify(aoo[i])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // create new array of objects from localStorage | 
					
						
							|  |  |  |     const new_aoo = []; | 
					
						
							|  |  |  |     for(var i = 0; i < localStorage.length; ++i) { | 
					
						
							|  |  |  |       const row = JSON.parse(localStorage.getItem(i)); | 
					
						
							|  |  |  |       new_aoo.push(row); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setOut(`Number of rows in LocalStorage: ${localStorage.length}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // create and export workbook | 
					
						
							|  |  |  |     const new_ws = XLSX.utils.json_to_sheet(new_aoo); | 
					
						
							|  |  |  |     const new_wb = XLSX.utils.book_new(); | 
					
						
							|  |  |  |     XLSX.utils.book_append_sheet(new_wb, new_ws, "Sheet1"); | 
					
						
							|  |  |  |     XLSX.writeFile(new_wb, "SheetJStorage.xlsx"); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  |   return ( <> | 
					
						
							| 
									
										
										
										
											2023-02-28 11:40:44 +00:00
										 |  |  |     {out && ( <><a href={url}>{url}</a><pre>{out}</pre></> )} | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  |     <b>URL: </b><input type="text" value={url} onChange={set_url} size="50"/> | 
					
						
							|  |  |  |     <br/><button onClick={xport}><b>Fetch!</b></button> | 
					
						
							|  |  |  |   </> ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | ## Simple Strings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The ["Row Objects" approach](#row-objects) is strongly recommended when trying | 
					
						
							|  |  |  | to store or recover arrays of row objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When the goal is to save an existing Storage, the general representation is an | 
					
						
							|  |  |  | array of pairs.  Consider the following data in Local Storage: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | Key | Value     | | 
					
						
							|  |  |  | |:---:|:----------| | 
					
						
							|  |  |  | | "b" | "Logical" | | 
					
						
							|  |  |  | | "n" | "Numeric" | | 
					
						
							| 
									
										
										
										
											2023-04-09 21:13:24 +00:00
										 |  |  | | "s" | "Textual" | | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The natural representation is an array of arrays: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | [ | 
					
						
							|  |  |  |   [ "b", "Logical" ], | 
					
						
							|  |  |  |   [ "n", "Numeric" ], | 
					
						
							|  |  |  |   [ "s", "Textual" ] | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Exporting Storage
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | :::note pass | 
					
						
							| 
									
										
										
										
											2023-04-09 21:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Web Storage iteration order is not defined.  By using indices as keys, the row | 
					
						
							|  |  |  | objects approach has an ordering.  That does not apply to the general case. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | In modern browsers, `Object.entries` will generate an array of key/value pairs. | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | The SheetJS `aoa_to_sheet`[^3] method will interpret that array as a worksheet | 
					
						
							|  |  |  | with 2 columns (key and value): | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function localStorage_to_ws() { | 
					
						
							|  |  |  |   const aoa = Object.entries(localStorage); | 
					
						
							|  |  |  |   return XLSX.utils.aoa_to_sheet(aoa); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Importing Storage
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In the other direction, the worksheet is assumed to store keys in column A and | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | values in column B. The SheetJS `sheet_to_json`[^1] method, with the option | 
					
						
							|  |  |  | `header: 1`, will generate key/value pairs that can be assigned to a storage: | 
					
						
							| 
									
										
										
										
											2023-02-26 11:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function ws_to_localStorage(ws) { | 
					
						
							|  |  |  |   const aoa = XLSX.utils.sheet_to_json(ws, { header: 1 }); | 
					
						
							|  |  |  |   aoa.forEach(([key, val]) => localStorage.setItem(key, val)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2023-04-09 21:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ### Live Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This example fills `localStorage` with 10 random keys and 10 random values, | 
					
						
							|  |  |  | generates a worksheet from the data and writes to a new file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Live Demo</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 21:13:24 +00:00
										 |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJSRandomStorage() { | 
					
						
							|  |  |  |   const [out, setOut] = React.useState(""); | 
					
						
							|  |  |  |   const [rows, setRows] = React.useState([]); | 
					
						
							|  |  |  |   const xport = React.useCallback(async() => { | 
					
						
							|  |  |  |     // reset and populate localStorage | 
					
						
							|  |  |  |     localStorage.clear(); | 
					
						
							|  |  |  |     var data = []; | 
					
						
							|  |  |  |     for(let i = 0, last = 0; i < 10; ++i) { | 
					
						
							|  |  |  |       var k = ((Math.random() * 20)|0) + last; | 
					
						
							|  |  |  |       var v = (Math.random() * 16777216).toString(36); | 
					
						
							|  |  |  |       localStorage.setItem(k, v); | 
					
						
							|  |  |  |       data.push([k,v]); | 
					
						
							|  |  |  |       last = k; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     setRows(Object.entries(localStorage)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // create new worksheet from localStorage | 
					
						
							|  |  |  |     const aoa = Object.entries(localStorage); | 
					
						
							|  |  |  |     const new_ws = XLSX.utils.aoa_to_sheet(aoa); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // create and export workbook | 
					
						
							|  |  |  |     const new_wb = XLSX.utils.book_new(); | 
					
						
							|  |  |  |     XLSX.utils.book_append_sheet(new_wb, new_ws, "Sheet1"); | 
					
						
							|  |  |  |     XLSX.writeFile(new_wb, "SheetJSRandomStorage.xlsx"); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   return ( <> | 
					
						
							|  |  |  |     {out && ( <><a href={url}>{url}</a><pre>{out}</pre></> )} | 
					
						
							|  |  |  |     {rows.length && (<table><tr><th>Key</th><th>Value</th></tr> | 
					
						
							|  |  |  |       {rows.map(([k,v]) => (<tr><td>{k}</td><td>{v}</td></tr>))} | 
					
						
							|  |  |  |     </table>) || null} | 
					
						
							|  |  |  |     <br/><button onClick={xport}><b>Export!</b></button> | 
					
						
							|  |  |  |   </> ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2023-09-18 06:44:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-06 02:51:20 +00:00
										 |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [^1]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output) | 
					
						
							|  |  |  | [^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input) | 
					
						
							|  |  |  | [^3]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input) |