DEV Community

Cover image for Simplify document cookies management
Phuoc Nguyen
Phuoc Nguyen

Posted on • Originally published at phuoc.ng

Simplify document cookies management

Cookies are tiny text files that websites store on your computer or mobile device when you visit them. These files contain information about your activity on the website, such as your login details, shopping cart contents, and browsing history. Websites use cookies to customize your experience, remember your preferences, and track your behavior.

A cookie looks like a key-value pair separated by an equals sign (=). You can store multiple keys and values in a single cookie by separating them with semicolons (;). Cookies also have attributes that determine when they expire, who can access them, and whether they should only be sent over secure connections.

In this post, we'll explore how to use JavaScript Proxy to manage cookies. But before we dive into that, let's go over some common tasks you can do with cookies.

Getting a cookie item

To retrieve a specific cookie item, you can use the document.cookie property. This property returns all cookies associated with the current document as a string separated by semicolons. To extract a specific value, you can use string manipulation methods such as split() and indexOf().

For instance, let's take a look at the following example cookie:

user=John; email=john@example.com; expires=Thu, 01 Jan 2022 00:00:00 UTC; path=/; domain=example.com
Enter fullscreen mode Exit fullscreen mode

To retrieve the value associated with the email key, simply use the following line of code:

const cookies = document.cookie.split('; ');
const emailCookie = cookies.find(cookie => cookie.startsWith('email='));
const emailValue = emailCookie.split('=')[1];
console.log(emailValue);    // "john@example.com"
Enter fullscreen mode Exit fullscreen mode

This code does a couple of things. First, it takes the document.cookie string and turns it into an array of separate cookies using the semicolon and space separator. Then, it finds the cookie that starts with the key "email". Once it finds that cookie, it separates out the value using another split operation and logs it to the console for you to see.

Setting a cookie item

To create or update a cookie, simply assign a string in the key=value format to the document.cookie property. You can also include additional attributes by appending semicolon-separated key-value pairs.

For instance, if you want to set a cookie with the key "username" and value "johndoe", you can use the following code:

document.cookie = "username=johndoe; expires=Thu, 01 Jan 2022 00:00:00 UTC; path=/";
Enter fullscreen mode Exit fullscreen mode

This code creates a cookie named "username" and gives it the value "johndoe". The cookie will expire on January 1st, 2022, and it will be accessible on any page with the path "/".

Deleting a cookie item

If you want to delete a cookie, simply set its expiration date to a date in the past. This will cause the cookie to expire immediately and be deleted by the browser.

For instance, if you want to delete the cookie with the key "username", you can use the following code:

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
Enter fullscreen mode Exit fullscreen mode

This code deletes a cookie named "username" from the user's browser. It does this by setting the value of the cookie to an empty string, setting its expiration date to January 1st, 1970 (which means it has already expired), and setting its path to "/".

It's important to note that if the cookie you want to delete has additional attributes, like domain or secure, you'll need to include those attributes in your deletion code as well.

Updating an existing cookie item

When you need to update an existing cookie, you can set the document.cookie property with the same name and path as before, but with a new value and expiration date if necessary. But let's face it, this approach can be repetitive and error-prone. The good news is that you can simplify the process by defining a reusable function that takes in the key, value, and expiration date as arguments and updates the corresponding cookie for you.

Here's an example implementation of such a function:

const updateCookie = (key, value, expires) => {
    const cookies = document.cookie.split('; ');
    const targetCookie = cookies.find(cookie => cookie.startsWith(`${name}=`));
    if (targetCookie) {
        const [key, value] = targetCookie.split('=');
        const attributes = targetCookie.slice(key.length + 1).split(';');
        const newAttributes = attributes.filter(attr => !attr.trim().startsWith('expires='));
        newAttributes.push(`expires=${expires.toUTCString()}`);
        document.cookie = `${key}=${value}; ${newAttributes.join('; ')}`;
    }
}
Enter fullscreen mode Exit fullscreen mode

This function creates a new string in the key=value format using the given parameters and sets it as the value of document.cookie. It's important to note that to update an existing cookie, you need to specify the same path as before. By calling this function, you can easily update a cookie without repeating the same code over and over again.

For instance, let's say you have a cookie named "theme" that stores the user's preferred color scheme for your website. If the user decides to switch from a "light" to a "dark" theme, you can update the corresponding cookie by calling this function.

// Expires in one day
updateCookie('theme', 'dark', new Date(Date.now() + 1000 * 60 * 60 * 24));
Enter fullscreen mode Exit fullscreen mode

This code sets the expiration of a cookie called "username" to one day from the current time.

Simplify cookie management with a custom wrapper

Managing cookies can be a hassle. To make it easier to interact with cookies, we'll create a custom cookie object that offers simple functions for managing cookies.

const cookies = {
  // The wrapper ...
};

// Get a cookie item
cookies.theme;

// Set a cookie
cookies.theme = 'dark';

// Remove a cookie item
delete cookies.theme;
Enter fullscreen mode Exit fullscreen mode

We'll be using JavaScript to create a wrapper for the document cookie using a proxy. A proxy lets you intercept and customize operations performed on an object, in this case, the document cookie. Here are the steps to use a proxy for managing cookies:

  • Create a Proxy object. Start by creating a Proxy object for the document cookie. This allows you to intercept and customize cookie operations.
  • Define a handler object. Next, define a handler object with methods for getting, setting, and deleting cookies.
  • Set the Proxy. Finally, set the Proxy to use the handler object. Now you can use the document cookie as usual, but with the added benefit of being able to customize cookie operations.

Here's a simple implementation of the Proxy traps handler:

const cookieHandler = {
    get: function(obj, prop) {
        ...
    },
    set: function(obj, prop, value) {
        ...
    },
    deleteProperty: function(obj, prop) {
        ...
    },
};
Enter fullscreen mode Exit fullscreen mode

This code creates a cookieHandler object that has three handy methods for working with cookies: getting, setting, and deleting. The get() method does a quick search through the document.cookie string to find the cookie with the name you specify, and then returns the decoded value of that cookie.

const cookieHandler = {
    get: function(obj, prop) {
        const cookies = document.cookie.split('; ');
        const cookie = cookies.find(cookie => cookie.startsWith(`${prop}=`));
        return cookie ? decodeURIComponent(cookie.split('=')[1]) : undefined;
    },
};
Enter fullscreen mode Exit fullscreen mode

The set() method allows you to create a fresh cookie with a specific name and encoded value.

const cookieHandler = {
    set: function(obj, prop, value) {
        document.cookie = `${prop}=${encodeURIComponent(value)}`;
        return true;
    },
};
Enter fullscreen mode Exit fullscreen mode

The deleteProperty() method is used to delete a cookie with a specific name. This is done by setting the cookie's expiration date to January 1st, 1970.

const cookieHandler = {
    deleteProperty: function(obj, prop) {
        document.cookie = `${prop}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;
        return true;
    },
};
Enter fullscreen mode Exit fullscreen mode

This line of code creates a new Proxy object that uses cookieHandler to handle an empty object.

const cookies = new Proxy({}, cookieHandler);
Enter fullscreen mode Exit fullscreen mode

You can now treat cookies like they're properties of an object, and interact with them accordingly.

// Get the value of a cookie item
cookies.theme;  // "dark"

// Set the value
cookies.theme = "light";

// Delete a cookie item
delete cookies.theme;
Enter fullscreen mode Exit fullscreen mode

This implementation utilizes the power of JavaScript Proxy to simplify and abstract away some of the complexities involved in managing cookies.

Adding expiration time support

To enhance our implementation and add support for expiration time for each cookie, we can modify the set() method of the cookieHandler object. To do this, we'll add an optional third argument for the expiration time. If this argument is provided, the method will convert it to a UTC string and append it to the cookie attributes before setting it.

Here's the updated implementation of the cookieHandler object with support for expiration times.

const cookieHandler = {
    // ...
    set: function(obj, prop, value) {
        const v = typeof value === "object" ? value.value : value;
        let attributes = [];
        if (typeof value === "object") {
            attributes.push(`expires=${value.expires.toUTCString()}`);
        }
        document.cookie = `${prop}=${encodeURIComponent(v)}; ${attributes.join('; ')}`;
        return true;
    },
};
Enter fullscreen mode Exit fullscreen mode

The updated version of the set() trap handler now accepts an optional third argument for the expiration time. If this argument is provided and it is an object, the method extracts the value property from the object and pushes an additional attribute to the cookie string that specifies its expiration date in UTC format.

To set a cookie with an expiration time, you can pass an object as the value parameter with two properties: value (the actual value of the cookie) and expires (a Date object representing when the cookie should expire). Here's how you would set a cookie named theme that expires in 30 days:

const expirationDate = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30);
cookies.theme = {
    value: "dark",
    expires: expirationDate,
};
Enter fullscreen mode Exit fullscreen mode

This code creates a new cookie called theme with a value of dark. It also sets an expiration date of 30 days from now by passing in an object with both value and expires properties as the second parameter.

To create a cookie that is deleted when the user closes their browser, we simply set it as a string, just like before.

cookies.username = 'johndoe';
Enter fullscreen mode Exit fullscreen mode

Conclusion

JavaScript Proxy is a powerful tool that simplifies the process of handling cookies in web development. With the cookieHandler object, you can easily get, set, and delete cookies without worrying about all the technical details involved in working with document.cookie.

By treating cookies as object properties, your code becomes more readable and easier to manage. You can even set expiration times for your cookies, making it possible to create cookies that expire at a specific time or never expire at all.

These tools are essential for building robust web applications that store user preferences and other data using browser cookies. Whether you're building a simple blog or a complex e-commerce site, managing cookies is a crucial part of web development. Using JavaScript Proxy to handle cookies simplifies the process and allows you to focus on delivering great user experiences.


If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

If you want more helpful content like this, feel free to follow me:

Top comments (0)