Giter VIP home page Giter VIP logo

use-cookie-consent's Introduction

useCookieConsent hook for pure JavaScript projects

Build NPM Version NPM Downloads Codecov gzipped size License

"Buy Me A Coffee"

Headless state management for GDPR cookie consent

  • Headless - bring your own styles, we will provide the logic.
  • Hook-based - extremely intuitive for React developers, but can be used in any JavaScript application.
  • Small - Less than 2kB gzipped.

carbon

Library-specific packages

This repo was made to be framework-agnostic, so you can use it in any JavaScript project. If you use a UI library that we support, you should use the package for your library for best experience

Description

This package is following this GDPR cookie guide which describes what you need for GDPR compliance. This hook mainly focuses handling the consent state of the different types of cookies as described in "Types of Cookies" in this page. Summarizing the mentioned document, there are three different ways to classify cookies:

  • Cookie Duration
    • Session cookies
    • Persistent cookies
  • Cookie Provenance
    • First-party cookies
    • Third-party cookies
  • Cookie Purpose
    • Strictly necessary cookies
    • Preferences cookies
    • Statistics cookies
    • Marketing cookies

The hook in this repository will provide a way to manage these types of cookies.

Installation

npm i @use-cookie-consent/core

yarn add @use-cookie-consent/core

pnpm add @use-cookie-consent/core

⚠️ Note: to have React v18 support, temporarily install @use-cookie-consent/[email protected]. All further development will support React v18, so this note will disappear in the future.

Usage in React

import { useCookieConsent } from '@use-cookie-consent/core';

export const YourComponent = () => {
  const { consent, acceptAllCookies, declineAllCookies, acceptCookies } =
    useCookieConsent();

  return (
    <div>
      <h3>
        {`Third-party cookies ${consent.thirdParty ? 'approved' : 'rejected'}`}
      </h3>
      <h3>
        {`First-party cookies ${consent.firstParty ? 'approved' : 'rejected'}`}
      </h3>

      <button onClick={acceptAllCookies}>Accept all</button>
      <button onClick={() => acceptCookies({ necessary: true, thirdParty: true })}>
        Accept third-party
      </button>
      <button onClick={() => acceptCookies({ necessary: true, firstParty: true })}>
        Accept first-party
      </button>
      <button onClick={declineAllCookies}>Reject all</button>
    </div>
  );
};

With custom cookie attributes

import { useCookieConsent } from '@use-cookie-consent/core';

export const YourComponent = () => {
  const { consent, acceptAllCookies, declineAllCookies, acceptCookies } = useCookieConsent({ 
      consentCookieAttributes: { expires: 180  } // 180 days
    }); 

  return (
    // ...
  );
};

Cookie attributes for the underlying js-cookie package, more info here.

API

useCookieConsent(options)

useCookieConsent is the main hook in this library. You call it whenever you need to accept, decline, set or get cookies - so anything to do with cookies.

useCookieConsent({
  defaultConsent?: CookieConsent,
  consentCookieAttributes?: CookieAttributes;
})

This hook function returns following object:

{
  consent: {
    session?: boolean;
    persistent?: boolean;
    necessary?: boolean;
    preferences?: boolean;
    statistics?: boolean;
    marketing?: boolean;
    firstParty?: boolean;
    thirdParty?: boolean;
  };
  acceptCookies: (cookies: CookieTypes) => void;
  declineAllCookies: () => void;
  acceptAllCookies: () => void;
  didAcceptAll: () => boolean;
  didDeclineAll: (opts?: CookieDeclineOptions) => boolean;
  cookies: CookieWrapper;
}

Roadmap to v1

  • Monorepo
  • Add package bundler (rollup was added)
  • Add support for Storage API
  • Add support for custom cookie categories
  • Create documentation website here
  • Create supporting library packages
    • React here
    • Vue (planned)
    • Svelte (planned)
    • Solid (planned)
    • Preact (planned)
    • Alpine (planned)
    • Lit (planned)
  • Change CookiesWrapper API to something that doesn't require a specific dependency (maybe just Storage API step?)

Contributing

If you want to contribute to this project, read our contributing guidelines first.

Acknowledgements

Following package was used as a starter for this project:

Discussions and Questions

For non-issues please consider joining our Discord here!

Contributors

License

MIT

use-cookie-consent's People

Contributors

bring-shrubbery avatar dependabot[bot] avatar edgarlr avatar monstrag avatar pixelass avatar stalkakuma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

use-cookie-consent's Issues

Add a didAcceptPrivacyOptions

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
There's a function for checking if they accepted all or declined all, but leaves out whether they accepted some

Describe the solution you'd like
A clear and concise description of what you want to happen.
Add a didAcceptPrivacyOptions so a cookie banner wouldn't pop up again if they already made their selection

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

`allowChangingNecessary` missing from the typedefs for `acceptCookies` function

useCookieConsent.ts:

const acceptCookies = (newConsent: CookieConsent, options?: AcceptCookiesOptions) => {
  if (options?.allowChangingNecessary) {
    setConsent(newConsent)
  } else {
    setConsent({...newConsent, necessary: true});
  };
};

types.ts:

export interface CookieConsentHookActions {
  acceptCookies: (cookies: CookieTypes) => void;
  ...
}

How to set the cookie as a persistent cookie?

Hi!
This is a great package, and really just what I needed for my cookie consent modal. However, I am unsure how to set the consent cookie as persistent?

Right now, If I use the function:

acceptCookies({
      necessary: true,
      preferences: false,
      statistics: true,
      marketing: false,
    });

It will set the cookie 'USE_COOKIE_CONSENT_STATE' as a session cookie. How do I set it as a persistent cookie (preferable with a 1 year expiration")?

Add package bundler

Is your feature request related to a problem? Please describe.
The code is currently only transpiled to JavaScript using TSC. It's not being minified, obfuscated, or optimized in any other way.

Describe the solution you'd like
Add package bundler like webpack or rollup (webpack would be my personal preference)

Describe alternatives you've considered
No reason not to add this, only benefits.

Add Cypress tests

I want to check if Cookies are set correctly.

So far I have tried various Jest mocks, but could not get the results I expected.

Supported engines: npm

Describe the bug
Package "core" does not support npm?

To Reproduce
Steps to reproduce the behavior:

  1. Install core or react package
  2. Get following message from npm:
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@use-cookie-consent/[email protected]',
npm WARN EBADENGINE   required: { node: '>=12', npm: '<0', yarn: '^1' },
npm WARN EBADENGINE   current: { node: 'v14.18.1', npm: '8.1.1' }
npm WARN EBADENGINE }

Expected behavior
No message like this

Desktop (please complete the following information):

  • OS: WSL on Windows 10

Additional context
Is there a reason for saying npm <0? Otherwise it seems to be easy to fix ;)

Retire Github Package Registry publishing

Is your feature request related to a problem? Please describe.

GPR is neither commonly used nor a very easy platform to access. It's great for having your own corporate packages stored in your own account, but not for a public package which goal is to be used widely by everyone. Additionally it needs extra maintenance and often breaks.

Describe the solution you'd like

Remove GPR publishing

Describe alternatives you've considered

none

Updated vulnerable dependencies.

As per Dependabot Alerts, there are two dependencies that make this repository vulnerable. You can find more info here.

These dependencies should be updated to latest versions.

Auto-detect version from release and auto-update it in the package.json

Is your feature request related to a problem? Please describe.

When creating a release, it's often annoying to set package.json version manually. This could be automated.

Describe the solution you'd like

The package.json version should be automatically set from the version that you set in the release.

Default Consent is not used

Describe the bug
The options.defaultConsent is not used.

Please review these lines:
https://github.com/bring-shrubbery/use-cookie-consent/blob/main/src/useCookieConsent.ts#L19-L21
https://github.com/bring-shrubbery/use-cookie-consent/blob/main/src/useCookieConsent.ts#L19-L21
https://github.com/bring-shrubbery/use-cookie-consent/blob/main/src/useCookieConsent.ts#L20

If the consent is not given an empty object is used. Therefore the defaultConsent from options will never be set.

  const initialConsent: CookieConsent =
    Cookies.getJSON(COOKIE_CONSENT_KEY) ?? EMPTY_CONSENT;

  const [consent, setConsent] = useState<CookieConsent>(
    initialConsent || options?.defaultConsent
  );

I noticed this when trying to add a server side defaultConsent into the provider described in #4

Use Case: Next.js

export const getServerSideCookieConsent = (
	context: GetServerSidePropsContext
): CookieConsent | null =>
	JSON.parse(context.req.cookies.USE_COOKIE_CONSENT_STATE ?? null) as CookieConsent;

As a workaround I adjusted my proposed Provider as follows:

export const CookieConsentProvider: FC<{ consent?: CookieConsent }> = ({
	children,
	consent: defaultConsent,
}) => {
	const {
		consent,
		acceptAllCookies,
		declineAllCookies,
		acceptCookies,
		didAcceptAll,
		didDeclineAll,
		cookies,
	} = useCookieConsent({ defaultConsent });

	const context = useMemo(
		() => ({
			consent: defaultConsent || consent,
			acceptAllCookies,
			declineAllCookies,
			acceptCookies,
			didAcceptAll,
			didDeclineAll,
			cookies,
		}),
		[
			consent,
			acceptAllCookies,
			declineAllCookies,
			acceptCookies,
			didAcceptAll,
			didDeclineAll,
			cookies,
			defaultConsent,
		]
	);

	return (
		<CookieConsentContext.Provider value={context}>{children}</CookieConsentContext.Provider>
	);
};

Usage:

import { CookieConsentProvider } from "path/to/my/cookie-consent-provider";
import React from "react";

const App = ({ Component, pageProps }) => {
  return (
      <CookieConsentProvider consent={pageProps.consent}>
        <Component {...pageProps} />
      </CookieConsentProvider>
  );
};

export default App;

Versions

use-cookie-consent: v0.1.12

Add support for custom cookie categories

Is your feature request related to a problem? Please describe.
Currently, you can only use specified cookie categories that are derived from GDPR guidelines. Although this is good enough to satisfy GDPR, it's always good to have the ability to extend that.

Describe the solution you'd like
Allow users of the hook to create new category types.

Configure monorepo and merge other repos into this one

Is your feature request related to a problem? Please describe.

Currently, you have to go through a number of different repositories to release multiple packages. Since library-specific libraries are dependent on the core package, the library-specific libraries should be updated with a patch version and updated core library dependency automatically when the core package is updated with the patch version. When the core package is updated with minor or major versions, then an issue should be added automatically for each library-specific package to update it with matching functionality. Documentation can also be auto-generated on library updates.

Describe the solution you'd like

Monorepo solves all this by making the atomic updates easy. It also removes the need to jump around the different repos.

Describe alternatives you've considered

Turborepo seems to be the best solution when compared to Lerna and Nx. Nx provides better performance, but the configuration is much more complex.

Warning about peer dependency with react 17

Describe the bug
When installing in a react 17.x project there are warnings about the peer dependencies

To Reproduce
Steps to reproduce the behavior:

  1. Create a project with react 17.x
  2. add this library
  3. install the dependencies
  4. See warning

Expected behavior
This library should not complain about react 17.x

20:03:37.385 | warning " > [email protected]" has incorrect peer dependency "react@^16.9".
20:03:37.386 | warning " > [email protected]" has incorrect peer dependency "react-dom@^16.9".

Versions

use-cookie-consent: v0.1.12

Add support for `Storage` API

Is your feature request related to a problem? Please describe.
Currently there's no way of changing where consent is being stored, nor there is a way to manage multiple storage options.

Describe the solution you'd like
Add web Storage API support, which would allow using anything for storing consent, including LocalStorage, SessionStorage, or a custom implementation, you could even implement it to store it on a server.

Example usage from user's perspective

User should be able to write following code to save things into localStorage instead of cookies:

const data = useCookieConsent({
  storage: localStorage
});

Or following to save it in sessionStorage:

const data = useCookieConsent({
  storage: sessionStorage
});

Or a custom Storage:

const data = useCookieConsent({
  storage: {
    getItem: () => ...,
    setItem: () => ...,
    etc...
  }
});

Necessary cookies are not always set to `true`

Describe the bug

  • When accepting just specific cookies, the necessary cookies are not set to true.
  • The initial true value does not persist when using acceptCookies.

More info can be found here: #18

Support React 18

Support latest React 18 version as peer dependency.

This should be as easy as adding:

"peerDependencies": {
    "react": "^16.8 || ^17 || ^18"
  },

into package.json file.

Thanks in advance ✌️

Add a cookie-consent-provider

Is your feature request related to a problem? Please describe.

Feature: Cookie Consent Provider

As a Developer, I want to use a context, so that my application has global access to the consent state

Describe the solution you'd like

Add a CookieConsentProvider (react-context).

Describe alternatives you've considered

I made my own Provider/Context.

Feel free to reuse my code as is. It nicely extends your existing API and adds a new hook useCookieConsentProvider.

I could open a PR for this, but probably not any time soon, since I am currently fully stuffed with work.

Example: https://codesandbox.io/s/eager-tree-by1dk
Demo: https://by1dk.csb.app/

import React, { createContext, FC, useContext, useMemo } from "react";
import { CookieConsentHookState, useCookieConsent } from "use-cookie-consent";

export const CookieConsentContext = createContext<CookieConsentHookState>({
	consent: {},
	acceptCookies() {
		/**/
	},
	declineAllCookies() {
		/**/
	},
	acceptAllCookies() {
		/**/
	},
	didAcceptAll() {
		return false;
	},
	didDeclineAll() {
		return false;
	},
	cookies: {
		set() {
			return undefined;
		},
		get() {
			return "";
		},
		getAll() {
			return {};
		},
		getJSON() {
			/**/
		},
		getAllJSON() {
			return {};
		},
		remove() {
			/**/
		},
	},
});

export const CookieConsentProvider: FC = ({ children }) => {
	const {
		consent,
		acceptAllCookies,
		declineAllCookies,
		acceptCookies,
		didAcceptAll,
		didDeclineAll,
		cookies,
	} = useCookieConsent();

	const context = useMemo(
		() => ({
			consent,
			acceptAllCookies,
			declineAllCookies,
			acceptCookies,
			didAcceptAll,
			didDeclineAll,
			cookies,
		}),
		[
			consent,
			acceptAllCookies,
			declineAllCookies,
			acceptCookies,
			didAcceptAll,
			didDeclineAll,
			cookies,
		]
	);

	return (
		<CookieConsentContext.Provider value={context}>{children}</CookieConsentContext.Provider>
	);
};

export const useCookieConsentContext = () => useContext(CookieConsentContext);

Additional context
I use the provider like this

import React from "react";
import {useCookieConsentContext, CookieConsentProvider} from "./CookieConsent";

export const CookieBanner = () => {
  const {acceptAllCookies, declineAllCookies, acceptCookies} = useCookieConsentContext();

  return (
    <div>
      <button onClick={acceptAllCookies}>Accept all</button>
      <button onClick={() => acceptCookies({thirdParty: true})}>
        Accept third-party
      </button>
      <button onClick={() => acceptCookies({firstParty: true})}>
        Accept first-party
      </button>
      <button onClick={declineAllCookies}>Reject all</button>
    </div>
  );
};

export const Cookies = () => {
  const {consent} = useCookieConsentContext();

  return (
    <div>
      <div>
        {`Third-party cookies ${consent.thirdParty ? 'approved' : 'rejected'}`}
      </div>
      <div>
        {`First-party cookies ${consent.firstParty ? 'approved' : 'rejected'}`}
      </div>

    </div>
  );
};

export default function App() {
  return (

      <CookieConsentProvider>
        <CookieBanner/>
        <Cookies/>
      </CookieConsentProvider>
  );
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.