(Updated: )
/ #alpinejs #javascript 

Sync Alpine.js x-data to localStorage/sessionStorage

Alpine.js is great for writing widgets. localStorage/sessionStorage are Web APIs that enable JavaScript application to store data beyond the life of the current JavaScript process.

This is useful for example if we wanted to persist our todos when the user closes the tab and comes back to it later.

If you want to skip to the examples, they’re in this CodePen collection or at the following:

Table of Contents

Sync a single string field to localStorage with Alpine.js x-init and $watch

In the following example, we initialise the message field to the msg localStorage property using localStorage.getItem('msg').

To sync state from Alpine.js to localStorage, we can use $watch('message', (val) => localStorage.setItem('msg', val)) in x-init. This will run the callback on every message change and therefore update the msg value in localStorage.

<div
  x-data="{ message: localStorage.getItem('msg') }"
  x-init="$watch('message', (val) => localStorage.setItem('msg', val))"
>
  <div><code>localStorage.getItem('msg')</code>: "<span x-text="localStorage.getItem('msg')"></span>"</div>
  <input x-model="message" />
  <div>Output: <span x-text="message"></span></div>
</div>

You can see the example working in the following CodePen:

See the Pen Alpine.js sync to localStorage - simple example by Hugo (@hugodf) on CodePen.

We’ve now seen how to sync a simple string between Alpine.js state and localStorage using x-init, $watch, localStorage.getItem and localStorage.setItem.

Next we’ll see how to sync an Array/Object between localStorage and Alpine.js using x-init, $watch, localStorage.removeItem and JSON.stringify/JSON.parse.

Sync an Array/Object to localStorage with Alpine.js x-init and $watch

The following is a full “todo” app with new todo and remove functionality.

Don’t use this in production, the way I’m generating id’s isn’t great 😂.

The interesting bits are as follows.

  1. In x-data, we do JSON.parse(localStorage.getItem('todos') || '[]'), that means that we try to parse what’s in localStorage under the 'todos' key, if it’s empty, parse '[]' (which parses to [], ie. an empty array).
  2. In x-init, we $watch the 'todos' Alpine.js data property. When the value updates, we run (val) => localStorage.setItem('todos', JSON.stringify(val)). We takes the full todos value and JSON.stringify it into localStorage.
  3. There’s a “new todo” form that can be submitted, and which would update the todos list.
  4. We loop through the “todos” using x-for, for each todo, we have a remove button which resets todos to all the current ones except the one for which we clicked the “remove” button.
<script>
  function badId() {
    return (Math.random() * 100).toFixed(0);
  }
</script>
<div
  x-data="{
    newTodo: '',
    todos: JSON.parse(localStorage.getItem('todos') || '[]')
  }"
  x-init="$watch('todos', (val) => localStorage.setItem('todos', JSON.stringify(val)))"
>
  <div>
    <code>localStorage.getItem('todos')</code>:
    <code x-text="localStorage.getItem('todos')"></code></div>
  <div>
    <button @click="todos = []; localStorage.removeItem('todos');">
      Clear
    </button>
  </div>

  <form
    @submit.stop.prevent="
      todos = [].concat({ id: badId(), text: newTodo }, todos);
      newTodo = '';
    "
  >
    <input x-model="newTodo" />
    <button>Add</button>
  </form>

  <ul>Todos:
    <template x-for="todo in todos" :key="todo.id">
      <li>
        <span x-text="todo.text"></span>
        <button @click="todos = todos.filter(t => t.id !== todo.id)">x</button>
      </li>
    </template>
  </ul>
</div>

You can see it in action at the following CodePen:

See the Pen Alpine.js sync to localStorage - persistent todo app by Hugo (@hugodf) on CodePen.

We’ve now seen how to sync more complex data structures between Alpine.js and localStorage.

Since sessionStorage has the same API, you can achieve something similar using that instead of localStorage.

That’s it for this post, you can check out the Alpine.js tag on Code with Hugo for more in-depth Alpine.js guides.

If you’re interested in Alpine.js, Subscribe to Alpine.js Weekly. A free, once–weekly email roundup of Alpine.js news and articles.

Photo by Steve Johnson on Unsplash

Author

Hugo Di Francesco

Co-author of "Professional JavaScript", "Front-End Development Projects with Vue.js" with Packt, "The Jest Handbook" (self-published). Hugo runs the Code with Hugo website helping over 100,000 developers every month and holds an MEng in Mathematical Computation from University College London (UCL). He has used JavaScript extensively to create scalable and performant platforms at companies such as Canon, Elsevier and (currently) Eurostar.

Interested in Alpine.js?

Subscribe to Alpine.js Weekly. A free, once–weekly email roundup of Alpine.js news and articles