npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

local-cookie-consent

v0.1.3

Published

Local-only React consent gating library with no backend and no network calls.

Readme

local-cookie-consent

A React + TypeScript component library for local-only cookie/script consent gating.

This package is designed for browser-local preference handling only:

  • no backend required
  • no network calls
  • no server-side consent storage
  • no generated visitor identifiers

Privacy-minimizing design

What this library stores

A local consent preference object with:

  • version
  • updatedAt
  • optional expiresAt
  • category decisions map

Example:

type ConsentState = {
  version: string;
  updatedAt: string;
  expiresAt?: string;
  categories: Record<string, boolean>;
};

What this library intentionally does not collect

  • IP address
  • user agent
  • visitor ID
  • session ID
  • account ID
  • email
  • geolocation
  • fingerprinting attributes
  • request headers
  • analytics events

Install

npm install local-cookie-consent

Basic setup

import {
  ConsentProvider,
  ConsentBanner,
  ConsentPreferencesModal,
  ConsentManageButton,
} from "local-cookie-consent";

const consentConfig = {
  version: "2026-06-privacy-v1",
  storageKey: "site_cookie_consent",
  categories: [
    {
      id: "necessary",
      label: "Necessary",
      description: "Required for the site to work.",
      required: true,
    },
    {
      id: "analytics",
      label: "Analytics",
      description: "Helps us understand site usage.",
    },
    {
      id: "marketing",
      label: "Marketing",
      description: "Used for advertising and conversion measurement.",
    },
  ],
};

export function App() {
  return (
    <ConsentProvider config={consentConfig}>
      <ConsentBanner policyLink={<a href="/privacy">Privacy policy</a>} />
      <ConsentPreferencesModal />
      <ConsentManageButton />
      {/* app content */}
    </ConsentProvider>
  );
}

Category configuration

type ConsentCategoryConfig = {
  id: string;
  label: string;
  description: string;
  required?: boolean;
  defaultValue?: boolean;
};

Rules:

  • required: true categories are always enabled
  • optional categories default to false unless explicitly configured otherwise
  • unknown categories are never treated as allowed

useConsent

const {
  consent,
  hasChoice,
  isAllowed,
  acceptAll,
  rejectAll,
  savePreferences,
  resetConsent,
  openPreferences,
} = useConsent();

Consent gating

Component gating

<ConsentGate category="analytics">
  <AnalyticsPanel />
</ConsentGate>

Script gating

<ConsentScript
  category="analytics"
  src="https://example.com/analytics.js"
  id="analytics-script"
/>

Callback gating

useConsentEffect("analytics", () => {
  // run only when analytics is allowed
});

Behavior:

  • optional categories are denied until explicit consent
  • stale version and expired consent force re-consent
  • reset/withdraw prevents future optional script injection

Storage adapters

The default storage is a first-party cookie:

  • SameSite=Lax
  • Path=/
  • Secure on HTTPS
  • configurable max age
  • non-HttpOnly (required for frontend reads)

You can provide your own storage adapter or use localStorage:

import { createLocalStorageAdapter } from "local-consent-gate";

const storage = createLocalStorageAdapter("site_cookie_consent");

<ConsentProvider config={consentConfig} storage={storage}>
  <App />
</ConsentProvider>;

Adapter interface:

interface ConsentStorage {
  read(): ConsentState | null;
  write(state: ConsentState): void;
  clear(): void;
}

Styling and theming

Default styles are included and use CSS variables defined in dist/index.css (source: src/styles/consent.css). You can customize look-and-feel by overriding the variables listed below or by providing your own stylesheet.

Common variables you may override:

  • --cc-bg
  • --cc-panel
  • --cc-primary
  • --cc-text

How to include the default CSS

  • Bundlers (Vite, Webpack, CRA, etc.) — import as a side-effect at app entry so the styles are bundled with your app:
// in your app's root entry (e.g. src/main.tsx or app/root.tsx)
import 'local-cookie-consent/styles.css';
  • Remix (links API) — use the ?url import to get the compiled asset URL and return it from links():
// app/root.tsx (Remix)
import consentStyles from 'local-cookie-consent/dist/index.css?url';

export const links = () => [
  { rel: 'stylesheet', href: consentStyles },
];

Notes on imports

  • local-cookie-consent/styles.css is the recommended simple import for most apps (side-effect import).
  • local-cookie-consent/dist/index.css?url or local-cookie-consent/styles?url returns an asset URL which is useful for frameworks that expect links()-style return values.
  • If your bundler complains about package exports during dev (Vite optimizeDeps), add the package to optimizeDeps.exclude or import the CSS into your app's public/ folder as a fallback.

No branding is hardcoded — everything uses CSS variables so you can fully control the appearance.

SSR notes

  • no direct window/document access during server render
  • storage interaction happens in client effects
  • optional categories are denied until a valid client-side consent state exists

Withdrawal/reset flow

Use resetConsent() to withdraw and clear saved consent locally. After reset, banner can be shown again and optional categories remain denied until new choice.

Versioning and re-consent

Re-consent is required when:

  • config.version changes
  • stored consent is malformed
  • stored consent is expired
  • required category constraints are invalid

Safe defaults:

  • malformed state is ignored
  • missing state means optional categories denied
  • stale/expired state asks again
  • new optional categories default to false

Limitations

  • This package does not maintain backend consent records.
  • This package does not prove consent for a specific user for backend audit trails.
  • Once third-party scripts run, complete cleanup can require page reload or integration-specific teardown.
  • This package is intended for local consent gating only.
  • Operators are responsible for deciding whether additional records are needed for their legal/compliance context.

Not legal advice

This package and documentation are technical guidance only and not legal advice.