You know everything about cookies, don't you ?

Cookies are used on the Web for almost 15 years now, and despite their numerous flows and the emerging alternatives brought by HTML5, developers still resort to them, mainly for their ease of use and consistent implementation across browsers. For example, as you might have noticed, the background colour of this page changes over the time. To keep the colour up to date across the different pages, the colour value is stored in a cookie. When a user is offered controls to increase or decrease the font sit on a site directly from a Web page, the same mechanism is used.

So far, the best technical documentation about cookies available on the Web was the one found on QuirksMode. It still appears as the number 1 result on google for the query: cookie Javascript. The related page on Wikipedia is a good source of information concerning all the drawbacks and the alternative to cookies. Although there are suitable alternatives when it comes identifying a client from a server, there is no widespread solutions working purely on the client-side (but I urge you to use a modern web browser and the gears plugin to get yourself ready for the next generation of Web applications). Anyway this documentation and the proposed algorithms are quite old, and the purpose of this post is to give the small update it deserves, and it will stick to client side use of cookies.

Writing a cookie

Cookies are just little text files managed by the browser that can be used to store key/value pairs. The maximum size of a cookie file for a given website is 4ko, preventing it to be used for anything else than small strings (a colour code, a font-size, a preferred language are perfectly fine). And this is the basic code to write your first cookie:

var cookie = "fontsize=19px";
document.cookie = cookie;

You just append a string composed of a key and a value separated by an “=” sign to the cookie property of the document.

By default, this cookie will be stored only as long as your browser remains opened and it will be available only on the same path of the same domain. If the address of the page is http://en.wikipedia.org/wiki/HTTP_cookie for example, cookies written from this page will be only available on pages with addresses beginning by en.wikipedia.org/wiki/, everything before the first “/” being the domain, and the rest being the path.

By the way, during the celebration of the 20th anniversary of the World Wide Web, Tim Berners-Lee admitted that he regretted the way Web addresses were constructed, and that the domain should start with the more general elements. Applied to the previous example, this would have lead to: /org/wikipedia/en/wiki/… (bringing the folder/sub-folder metaphor to the Web).

It is possible to change those defaults by adding parameters at the end of your cookie String.

Expiry date

It is possible to specify explicitly the date when the cookie will be trashed by the browser, using the expires parameter and a Date object serialized by the Date.toUTCString() method (and not the deprecated toGMTString one):

var day = new Date(),
expiryDate = "expires=" + day.toUTCString();

In modern browsers, it is alternatively possible to set the max-age of a cookie in seconds, but this parameter is unfortunately unavailable in Internet Explorer (just like so many other things that would make the Web developer’s life easier).

Path and domain

It’s a good practice to set the path to the highest level:

var path = "path=/";

I can’t foresee any serious security issue resulting from this practice (considering that cookies should never be used to store critical data). And on the other hands you are likely to be unable to erase a particular cookie written by a script not specifying any path.

If there is no sub-domains for your website, the domain parameter is not useful. But in the Wikipedia example, the domain should be set as follows to be able to use the cookies across sub-domains:

var domain = "domain=wikipedia.org";

All-together

Writing a cookie with those parameters can be achieved with the following code:

var day = new Date();
document.cookie = "fontsize=19px" +";"+
"expires=" + day.toUTCString() +";"+
"domain=wikipedia.org +";"+
"path=/";

As you can notice, parameters should be separated by a “;”. Note that so far the Date used is a new, unmodified date, which represent the current date. Setting a expiry date to the current date is not gonna make your cookie last long. The solution will be provided in the scripts.

It is not possible to write two cookies at a time.

document.cookie = "fontsize=19px; fontcolor=#0000FF";

This code would actually write only the first key/value pair. You have to write the second cookie on a separated line beginning with document.cookie. Considering the parameters string to add to each cookie, the need of code factorisation is easy to understand.

Reading a cookie

Reading a particular cookie value can be achieved by reading the cookie string of the website and extracting a single value pair using a regular expression based on a key.

result = new RegExp("(?:^|; )" +key+ "=([^;]*)”).exec(document.cookie);
var value = result[1];

Special characters

In order to be able to read and write values potentially containing special characters (such as a “;” that would split your value), the value should be encoded before being written and decoded after being read.

document.cookie = encodeURIComponent("special=abc;def");
result = new RegExp("(?:^|; )" +"special"+ "=([^;]*)”).exec(document.cookie);
var value = decodeURIComponent(result[1]);

Overwrite and delete cookies

To overwrite a cookie simply write a new cookie with the same key.

document.cookie = "key=firstValue";
document.cookie = "key=secondValue";
// When reading "key", you'll find "secondValue"

The best way to erase a cookie is to overwrite it with an empty value and a past expiry date

var day = new Date();
// set the date to yesterday
day.setDate(day.getDate() -1);
document.cookie = "key=" +";"+
"expires=" + day.toUTCString();

The scripts

Using the previous pieces of code, it is possible to create a small cookie library that will handle writing/reading/erasing a cookie with a single function.

function cookieLib(key, value, expiryDay) {
  // If there is not just a key, the function is used to write a cookie
  if(arguments.length >1) {
    // But if the value is null, the function is used to erase a cookie
    if (value === null) {
      value = '';
      expiryDay = -1;
    }
    // If the date parameter is a number,
    // create a date from today + this number of days
    if (typeof expiryDay == "number") {
      var day = new Date();
      day.setDate(day.getDate() + expiryDay);
      expiryDay = day;
    }
    // Create the cookie string
    document.cookie = [
      key , '=' , encodeURIComponent(value),
      '; expires=' , expiryDay.toUTCString(),
      '; path=/'
    ].join("");
  // If there was only a key, the function is used to read a value
  } else if(result = new RegExp("(?:^|; )" +key+ "=([^;]*)")
           .exec(document.cookie))
    return decodeURIComponent(result[1]);
  return false;
};

Remember that cookies are only meant to store string values. If you want to write a number, remember to parse it back to a number after reading it.

I’ve also turned this cookie library in a plugin for the famous jQuery library, check the code of jquery.cookie on github.