All hooks / Storage and URL

useCookie

446 B minified and brotliedSourceMarkdown✓ Works in all modern browsers

A cookie's value, a setter, and a remover. Unlike browser-only state, a cookie also reaches the server with the request: pass the request's value as serverValue, and the server render, hydration, and the browser all agree from the first frame.

Re-renders when the cookie changes through this hook (in any component), through the Cookie Store API's change event where the browser supports it, and when the window regains focus, which catches changes made by the server or another tab elsewhere. Values are strings, URL-encoded on write.

Import

import { useCookie } from '@vincent.ri/react-tils'
// or only this hook
import { useCookie } from '@vincent.ri/react-tils/useCookie'

Usage

// Server component: read the cookie from the request and pass it down.
const theme = (await cookies()).get('theme')?.value ?? null
return <ThemeToggle serverTheme={theme} />

// Client component
function ThemeToggle({ serverTheme }: { serverTheme: string | null }) {
  const [theme, setTheme] = useCookie('theme', serverTheme)
  const next = theme === 'dark' ? 'light' : 'dark'
  return <button onClick={() => setTheme(next, { maxAgeSeconds: 60 * 60 * 24 * 365 })}>{next}</button>
}

Live demo

Set it, then reload: the cookie is still there, and sent to the server too.

demo-theme: not set

When to use it

A preference the server must also know on the first request, so it can render the right thing: theme, locale, currency, a dismissed banner, or an A/B test bucket.

When not to

The value is sensitive (session tokens); set those as HttpOnly cookies on the server, which JavaScript can't read at all. For client-only state, useLocalStorage holds more and doesn't ride along on every request.

API

function useCookie(name: string, serverValue?: string | null): [string | null, (value: string, options?: CookieOptions) => void, (options?: CookieOptions) => void]
ParameterDescription
nameThe cookie name.
serverValueThe value on the server and during hydration: read it from the request (e.g. (await cookies()).get('theme')?.value in Next.js). Default null.

Returns [value, set, remove]. set(value, options?) writes the cookie; remove(options?) deletes it (pass the same path and domain it was set with).

Types

export type CookieOptions = {
  /** Lifetime in seconds. Default: until the browser session ends. */
  maxAgeSeconds?: number;
  /** Default `'/'`, so the whole site sees it. */
  path?: string;
  domain?: string;
  /** Default `'lax'`. */
  sameSite?: "strict" | "lax" | "none";
  /** Send only over HTTPS. Default: `true` on HTTPS pages. Required with `sameSite: 'none'`. */
  secure?: boolean;
};

Browser support

UsesChromeEdgeFirefoxSafariChrome AndroidSafari iOS
document.cookieWidely available1+12+68+4+18+3.2+
Cookie Store APIoptionalNewly available87+87+140+18.4+87+18.4+
  • Changes made outside the hook are noticed right away where the Cookie Store API exists, and otherwise when the window regains focus.

Optional features are used when present; without them the hook still works.

First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).

Coming from another library?

Other libraries call this useCookies (react-cookie), useCookieState.