> For the complete documentation index, see [llms.txt](https://docs.wem.io/platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wem.io/platform/tutorials/building-widgets/in-depth/5-view-state/2-sessionstorage.md).

# 2. sessionStorage

{% hint style="info" %}
A CSP-compliant version is available for download on the [Examples](/platform/tutorials/building-widgets/examples.md) page.
{% endhint %}

You can also utilize `sessionStorage` and `localStorage`, which are available in the JavaScript standard library. These solutions are purely JavaScript-based and do not rely on WEM view state internals.

Keep in mind that storing state in `sessionStorage` or `localStorage` is permanent throughout the browser session or on your local machine. This can be a useful feature. However, if you want to clean up the view state, you need to do that manually, which can be quite tricky to implement.

Let's update our previous widget slightly.

Update the script with the following:

```html
<div id="<?attr OutputId() ?>" class="message">
	<span class="box ellipses">
		<span class="glyphicon glyphicon-comment"></span> 
		...
	</span>
	<span class="box text">
		<span class="glyphicon glyphicon-heart-empty"></span>
		<?= @Text ?>
	</span>
</div>
<? scriptmodule "wem-message-box" ?>

	function clearStateMessageBox(outputId, nodeId) {
		const key = getKeyMessageBox(outputId, nodeId);
		sessionStorage.removeItem(key);
	}

	function getKeyMessageBox(outputId, nodeId) {
		return `${outputId}:${nodeId}:collapsed`;
	}

	function initializeMessageBox(outputId, nodeId, style) {
		const element = document.getElementById(outputId);
		
		const key = getKeyMessageBox(outputId, nodeId);
		const collapsed = sessionStorage.getItem(key) === "yes";

		element.classList.add(style);
		element.classList.toggle("collapsed", collapsed);
		element.classList.toggle("expanded", !collapsed);
		
		element.addEventListener("click", () => toggleMessageBox(element, key));
	}

	function toggleMessageBox(element, key) {
		element.classList.toggle("collapsed");
		element.classList.toggle("expanded");
	
		const collapsed = element.classList.contains("collapsed");
		
		sessionStorage.setItem(key, collapsed ? "yes" : "no");
	}
	
<? end ?>
<?
	/* Unfortunately, WEM does not yet have a NodeId() function. */
	var @currentNodeId := Last(Split(NodeTrail(), ","))
?>
<? startupscript ?>

	initializeMessageBox(<?js OutputId() ?>, <?js @currentNodeId ?>, <?js @Style ?>);

<? end ?>
```

In this update, we introduce `startupscript`, which is a JavaScript code block that runs after the page has been initialized and all static HTML elements are rendered. There are others like these and we will discuss these script blocks in more detail in later chapters.

Comparing the previous code with the new version, you will notice that the `initializeMessageBox()` function is used to initialize the message box, as the name suggests. Here, we set the class names and retrieve the view state using `sessionStorage` through JavaScript. Additionally, we updated the code to set the `click` handler here instead of using an `onclick` attribute. While functionally there is no difference, this approach promotes better organization, a principle known in computer science as "separation of concerns."

Looking at the function `getKeyMessageBox(outputId, nodeId)` and the line ``const key = `${element.id}:${nodeId}:collapsed`;`` , we see that the `key` is created by combining the Output ID, a node ID, and an arbitrary identifier, separated by a colon. Since `sessionStorage` keys are stored globally, we need to ensure that the keys for this widget are globally unique. If we had simply used "collapsed" as the key and had two identical widgets on the same page, they would overwrite each other's state. The node ID ensures that the view state of this widget is unique per interaction node. While we use a colon here, any character that is not alphanumeric can be used, as those characters are reserved for the Output ID and node ID.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.wem.io/platform/tutorials/building-widgets/in-depth/5-view-state/2-sessionstorage.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
