CodingNic

Browser APIs

Cookies

Browser APIs 15 min read

Cookies

Objectives

By the end of this chapter, you should be able to:

  • Read and write a cookie with document.cookie
  • Delete a cookie by setting its expiration in the past
  • Explain when a cookie is a better fit than localStorage

๐Ÿ’ก Why this matters: Cookies predate localStorage by two decades, and they still do one thing localStorage can’t: get automatically sent to the server with every request. That makes them the right tool for a specific, common job, even in a modern project.

What You’re Building

A cookie consent banner, the kind almost every site shows a first-time visitor, plus a dark mode toggle that remembers its setting the same way.

text
cookie-demo/
โ”œโ”€โ”€ index.html
โ””โ”€โ”€ script.js
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Cookie Preferences Demo</title>
</head>
<body>
  <h1>Welcome</h1>

  <div id="consentBanner">
    <p>We use cookies to remember your preferences.</p>
    <button id="acceptBtn">Accept</button>
  </div>

  <button id="darkModeBtn">Toggle Dark Mode</button>

  <script src="script.js"></script>
</body>
</html>

Everything from here on goes in script.js.

document.cookie reads every cookie as one semicolon-separated string, so reading a specific one takes a small amount of parsing first.

javascript
function getCookies() {
  return Object.fromEntries(
    document.cookie.split("; ").filter(Boolean).map((pair) => pair.split("="))
  );
}

const banner = document.getElementById("consentBanner");

function checkConsent() {
  const cookies = getCookies();
  if (cookies.consent === "true") {
    banner.style.display = "none";
    return true;
  }
  banner.style.display = "block";
  return false;
}

checkConsent();

On a first visit, there’s no consent cookie yet, cookies.consent is undefined, and the banner shows. .split("; ") breaks the raw cookie string into "name=value" pairs, .map((pair) => pair.split("=")) breaks each of those into a [name, value] array, and Object.fromEntries() (Course 1) turns the whole list into a plain object you can check properties on.

javascript
const acceptBtn = document.getElementById("acceptBtn");

acceptBtn.addEventListener("click", () => {
  document.cookie = "consent=true; expires=Fri, 31 Dec 2027 00:00:00 UTC; path=/";
  banner.style.display = "none";
});

Clicking “Accept” writes a consent cookie, expires set a couple of years out, and hides the banner immediately, no reload required. path=/ makes the cookie available on every page of the site, not just whichever page set it, the most common value for path.

Writing a new cookie never erases the others, document.cookie = "..." adds or updates one cookie at a time.

javascript
const darkModeBtn = document.getElementById("darkModeBtn");

darkModeBtn.addEventListener("click", () => {
  const cookies = getCookies();
  const isDark = cookies.theme === "dark";
  document.cookie = `theme=${isDark ? "light" : "dark"}; path=/`;
});

Clicking “Toggle Dark Mode” now sets a second, independent cookie, theme, right alongside consent. After accepting cookies and toggling dark mode once, document.cookie holds both: "consent=true; theme=dark".

There’s no dedicated delete method for a cookie, deleting one means overwriting it with an already-expired date.

javascript
function revokeConsent() {
  document.cookie = "consent=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
  banner.style.display = "block";
}

Calling revokeConsent() removes the consent cookie (the browser drops any cookie whose expiration has passed) and brings the banner back, exactly as if this were a first visit again. Notice theme is untouched, revokeConsent() only rewrites the consent cookie, nothing else.

Cookies vs. localStorage

This banner could have been built with localStorage instead, so why cookies? A cookie is automatically included in every HTTP request to its site, which matters the moment a server needs to know about it too, session identifiers, authentication tokens, anything the backend has to see on every request. localStorage is never sent to the server at all, it only exists for the page’s own JavaScript. A consent banner is genuinely a case where either works, this lesson used cookies because it’s the classic example, but a login session token is a case where only a cookie will do.

The Complete script.js

javascript
function getCookies() {
  return Object.fromEntries(
    document.cookie.split("; ").filter(Boolean).map((pair) => pair.split("="))
  );
}

const banner = document.getElementById("consentBanner");
const acceptBtn = document.getElementById("acceptBtn");
const darkModeBtn = document.getElementById("darkModeBtn");

function checkConsent() {
  const cookies = getCookies();
  if (cookies.consent === "true") {
    banner.style.display = "none";
    return true;
  }
  banner.style.display = "block";
  return false;
}

checkConsent();

acceptBtn.addEventListener("click", () => {
  document.cookie = "consent=true; expires=Fri, 31 Dec 2027 00:00:00 UTC; path=/";
  banner.style.display = "none";
});

darkModeBtn.addEventListener("click", () => {
  const cookies = getCookies();
  const isDark = cookies.theme === "dark";
  document.cookie = `theme=${isDark ? "light" : "dark"}; path=/`;
});

Try It

Extend the consent banner from this lesson:

  1. Add a "declined" state: a “Decline” button that sets consent=false (instead of true) and still hides the banner, without ever showing the dark mode toggle’s effect (skip actually applying a theme, just track the cookie).
  2. Change checkConsent() so it also reads the theme cookie on load and logs `Theme preference: ${cookies.theme}` if one exists.
  3. Add a “Reset everything” button that deletes both the consent and theme cookies in one click, and confirm document.cookie is empty afterward.

Recap

  • document.cookie reads every cookie as one string, writing to it adds or updates a single cookie without clearing the rest, this lesson’s accept and dark-mode buttons each set their own cookie independently.
  • expires controls when a cookie is removed automatically, path=/ makes it available across the whole site.
  • There’s no delete method, setting a cookie with a past expires removes it, exactly what revokeConsent() did.
  • Cookies are sent with every request to the server, localStorage never is, that’s the deciding factor between them.

Next lesson: the Geolocation API, asking the browser for the user’s physical location.