Learn how the Cookie Store API modernizes cookie management with async operations and event handling for efficient, error-free web development.
The browser Cookie Store API represents a modern approach to handling cookies in web applications. The way we’ve always done it is using document.cookie
which is error-prone because you have to work with key/value pairs in a string. Besides being error-prone, it’s a synchronous, blocking operation, which doesn’t fit modern patterns whereby we try to move certain operations to be asynchronous and out of the main thread. It depends on the document
object, therefore it can’t be used in a Service Worker context.
This tutorial explores how this new API simplifies cookie management. We’ll build a site with light and dark themes, allowing users to switch themes and store their preferences in a cookie for future visits.
Traditionally, web developers have used the document.cookie
API to work with cookies. Here’s how we used to handle cookies:
// Setting a cookie
document.cookie = "theme=dark; expires=Fri, 31 Dec 2024 23:59:59 GMT; path=/";
// Reading cookies
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
// Using the cookie
const theme = getCookie('theme');
if (theme === 'dark') {
document.body.classList.add('dark-theme');
}
At first glance, setting cookies with document.cookie
feels like we’re overwriting the entire cookie value. The string manipulation needed to read a cookie value is cumbersome, and a small mistake can break your application. Handling multiple cookies means parsing the cookie string over and over, and due to its synchronous nature, this could slow down your application.
The Cookie Store API on the other hand addresses those issues by providing a promise-based interface with these advantages:
Let’s see how to build a theme switcher that demonstrates how to use the Cookie Store API. Our example will allow users to toggle between light and dark themes, with their preference persisting across page reloads and browser sessions.
First, let’s look at the HTML structure:
<div class="container">
<h1>CookieStore API Demo</h1>
<button class="theme-switcher" onclick="toggleTheme()">Toggle Theme</button>
<div class="cookie-info">
<h3>Current Cookie State:</h3>
<div id="cookieDisplay"></div>
</div>
</div>
Now, let’s implement the core functionality using the CookieStore
interface:
// Check if CookieStore API is supported
if ('cookieStore' in window) {
// Listen for cookie changes
cookieStore.addEventListener('change', event => {
console.log('Cookie change detected:', event);
updateCookieDisplay();
});
}
// Initialize theme on page load
async function initializeTheme() {
try {
const themeCookie = await cookieStore.get('theme');
if (themeCookie && themeCookie.value === 'dark') {
document.body.classList.add('dark-theme');
}
updateCookieDisplay();
} catch (error) {
console.error('Error reading theme cookie:', error);
}
}
// Toggle theme and save preference
async function toggleTheme() {
const isDarkTheme = document.body.classList.toggle('dark-theme');
try {
await cookieStore.set({
name: 'theme',
value: isDarkTheme ? 'dark' : 'light',
expires: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days
sameSite: 'strict'
});
} catch (error) {
console.error('Error saving theme preference:', error);
}
}
Let’s break down the key features:
Async/Await Pattern: The API uses promises, making it compatible with async/await syntax. This results in cleaner code compared to callback-based approaches.
Cookie Change Detection: The CookieStore
interface provides an event listener for listening to cookie changes. This allows us to react to cookie modifications in real-time.
Simplified Reading and Writing: Notice how we can directly get and set cookies using methods like set()
, get()
and getAll()
without string manipulation.
Here’s the complete code for you to try yourself and a demo of how it works.
As of 2024, the CookieStore API is not universally supported across all browsers. Chrome and Edge support it, while Firefox and Safari are still working on implementation.
Image from MDN
For production applications, you should implement a fallback mechanism. You should check if cookieStore
is available in the Window
object. Here’s an example:
class CookieManager {
constructor() {
this.useModernAPI = 'cookieStore' in window;
}
async setCookie(name, value, options = {}) {
if (this.useModernAPI) {
return cookieStore.set({ name, value, ...options });
}
// Fallback to traditional approach
let cookie = `${name}=${value}`;
if (options.expires) {
cookie += `; expires=${new Date(options.expires).toUTCString()}`;
}
if (options.path) {
cookie += `; path=${options.path}`;
}
document.cookie = cookie;
}
async getCookie(name) {
if (this.useModernAPI) {
return cookieStore.get(name);
}
// Fallback implementation
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return {
name,
value: parts.pop().split(';').shift()
};
}
return null;
}
}
This example defines a class with two methods getCookie()
and setCookie()
. These methods use the CookieStore
methods if available; otherwise, they fall back to document.cookie
.
The Cookie Store API significantly improves cookie handling. Its promise-based interface, built-in change detection and cleaner methods make it a powerful tool for modern web development. While browser support is still growing, implementing it with appropriate fallbacks allows you to write durable code while being future-ready. Check the MDN documentation for more information about the Cookie Store API.
Peter is a software consultant, technical trainer and OSS contributor/maintainer with excellent interpersonal and motivational abilities to develop collaborative relationships among high-functioning teams. He focuses on cloud-native architectures, serverless, continuous deployment/delivery, and developer experience. You can follow him on Twitter.