Cookie Management

A React/Zustand module for cookie consent, for conditional rendering components based on user consent, with context for global state management. This is a collection of React Components and Typescript Functions that together serve a specific purpose.

Preview

This is how the code looks like in action.

Heads up!

We use cookies to enhance the functionality of this website in order to give you the best experience. Cool?

Learn more in ourPrivacy Policy and ourCookie Policy

Step-By-Step Guide

1. Install Dependencies

State management by Zustand

cli

1npm install zustand

Icons by Lucide. But you can use any or none.

cli

1npm install lucide-react

Button component by shadcn/ui

cli

1npx shadcn-ui@latest add button

Copy the function 'cn'. Link -> cn Function

2. Copy the Source Code

  1. The persistent store

@/state/useCookieConsentStore.ts

1// Purpose: Store for managing the cookie consent
2
3// Import Types
4// Import External Packages
5import { create } from 'zustand';
6import { createJSONStorage, persist } from 'zustand/middleware';
7// Import Components
8// Import Functions & Actions & Hooks & State
9// Import Data
10// Import Assets & Icons
11
12interface CookieConsentState {
13	hasCookieConsent: boolean | null;
14	setCookieConsent: (hasConsent: boolean | null) => void;
15}
16
17export const useCookieConsentStore = create(
18	persist<CookieConsentState>(
19		(set) => ({
20			hasCookieConsent: null,
21			setCookieConsent: (hasCookieConsent: boolean | null) =>
22				set({ hasCookieConsent }),
23		}),
24		{
25			name: 'cookie-consent',
26			storage: createJSONStorage(() => localStorage),
27		}
28	)
29);
  1. The hook

@/state/useCookieConsent.ts

1// Purpose: Custom hook to manage cookie consent
2
3// Import Types
4// Import External Packages
5// Import Components
6// Import Functions & Actions & Hooks & State
7import { useCookieConsentStore } from '@/state/useCookieConsentStore';
8// Import Data
9// Import Assets & Icons
10
11export function useCookieConsent() {
12	const { hasCookieConsent, setCookieConsent } = useCookieConsentStore();
13
14	const acceptCookies = () => setCookieConsent(true);
15	const denyCookies = () => setCookieConsent(false);
16
17	return {
18		hasCookieConsent,
19		acceptCookies,
20		denyCookies,
21	};
22}
  1. The Banner

@/components/CookieConsentBanner.tsx

1'use client';
2
3// Import Types
4// Import External Packages
5import { useState, useEffect } from 'react';
6import Link from 'next/link';
7// Import Components
8import { Button, ButtonProps } from '@/ui/Button';
9// Import Functions & Actions & Hooks & State
10import { useCookieConsent } from '@/state/useCookieConsent';
11import { cn } from '@/lib/utils';
12// Import Data
13// Import Assets & Icons
14import { CookieIcon } from 'lucide-react';
15
16export function CookieConsentButton_Accept({
17	buttonText = 'Accept',
18	variant = 'default',
19	className,
20}: {
21	buttonText?: string;
22	variant?: ButtonProps['variant'];
23	className?: string;
24}) {
25	const { acceptCookies } = useCookieConsent();
26
27	return (
28		<Button
29			variant={variant}
30			onClick={acceptCookies}
31			className={cn(className)}
32		>
33			{buttonText}
34		</Button>
35	);
36}
37
38export function CookieConsentButton_Deny({
39	buttonText = 'Deny',
40	variant = 'secondary',
41	className,
42}: {
43	buttonText?: string;
44	variant?: ButtonProps['variant'];
45	className?: string;
46}) {
47	const { denyCookies } = useCookieConsent();
48
49	return (
50		<Button
51			variant={variant}
52			onClick={denyCookies}
53			className={cn(className)}
54		>
55			{buttonText}
56		</Button>
57	);
58}
59
60/**
61 * Renders a cookie consent banner component.
62 * The banner is displayed to users who have not yet given their consent to use cookies, and only appears after first scroll.
63 */
64export default function CookieConsentBanner() {
65	const { hasCookieConsent } = useCookieConsent();
66	const [showOnScroll, setShowOnScroll] = useState(false);
67
68    // Note: This prevents the banner from flickering when a user that previously provided consent returns to the website.
69	useEffect(() => {
70		const handleFirstScroll = () => {
71			setShowOnScroll(true);
72			window.removeEventListener('scroll', handleFirstScroll);
73		};
74
75		if (hasCookieConsent === null) {
76			window.addEventListener('scroll', handleFirstScroll);
77		}
78
79		return () => {
80			window.removeEventListener('scroll', handleFirstScroll);
81		};
82	}, [hasCookieConsent]);
83
84	if (hasCookieConsent !== null || !showOnScroll) return null;
85
86	return (
87		<div className="fixed left-6 bottom-6 shadow-lg shadow-neutral-500 z-50 max-w-96 bg-white dark:bg-dark-gray dark:text-white p-4 rounded-md">
88			<h2 className="text-lg font-semibold inline-flex leading-6 py-2">
89				Heads up! <CookieIcon className="mx-2" />
90			</h2>
91			<p className="text-muted-foreground">
92				We use cookies to enhance the functionality of this website in order to
93				give you the best experience. Cool?
94			</p>
95			<p className="py-2 text-muted-foreground">
96				Learn more in our
97				<Link
98					href="/privacy-policy"
99					className="underline whitespace-nowrap px-2"
100				>
101					Privacy Policy
102				</Link>{' '}
103				and our
104				<Link
105					href="/cookie-policy"
106					className="underline whitespace-nowrap px-2"
107				>
108					Cookie Policy
109				</Link>
110			</p>
111			<div className="grid justify-items-end">
112				<div className="space-x-2">
113					<CookieConsentButton_Deny />
114					<CookieConsentButton_Accept />
115				</div>
116			</div>
117		</div>
118	);
119}

3. Use in your App

  1. Add Banner to global layout

layout.tsx

1import CookieConsentBanner from '@/components/CookieConsentBanner';
2
3export default async function RootLayout({
4	children,
5}: Readonly<{
6	children: React.ReactNode;
7}>) {
8  return (
9     {/* The rest of your HTML components */}
10        <body>
11            <CookieConsentBanner />
12            {/* The rest of your app components */}
13        </body>
14     {/* The rest of your HTML components */}
15  );
16}
  1. Make components dependent on user consent

@/components/SomeComponent.tsx

1import { useCookieConsent } from '@/state/useCookieConsent';
2
3const CookieDependentComponent = () => {
4  const { hasConsent } = useCookieConsent();
5
6  if (!hasConsent) return null; 
7
8  return <div>Cookie-dependent content here</div>;
9};

Tech Stack

Only the finest ingredients are used in our products. We made sure that we only use the best technologies available which offer a free tier! Yes, you read that right. Everything can be set up for FREE!

Lucide

Lucide

A simply beautiful icon library.

Icons

Tailwind

Tailwind

The most popular CSS framework. It is easy to use, well documented and has a great community.

CSS Framework

shadcn/ui

shadcn/ui

Beautifully designed open-source component library

UI Library

React

React 18

The library for web and native user interfaces

Web Library

Zustand

Zustand is a small, fast and scalable bearbones state-management solution using hooks

State Management

Example Usage

See this component live in action. Are you using the component on your website? Shoot us an email (support@boilerplatehq.com) and we will link to you.

BoilerplateHQ
External link to https://boilerplatehq.com

BoilerplateHQ

We use this as our cookie banner and management component!

Example Usage of React Component

Your Website?

Are you using this component? Shoot us an email and we will link to you.

You May Also Like

Didn't find what you were looking for? Check out these other items.

Ui Component Library Template
Internal link to /templates/ui-component-library
Templates

Ui Component Library

Want to create your own Ui Component Library like shadcn/ui? This is your template!

Back To Top Button | BoilerplateHQ
Internal link to /components/button-back-to-top
Components

Button BackToTop

Renders a button component that scrolls the page to the top when clicked.

Breadcrumps React Component | BoilerplateHQ
Internal link to /components/breadcrumps
Components

Breadcrumps

Renders a breadcrumb component that displays the current page's path.

Frequently Asked Questions

We have compiled a list of frequently asked questions. If you have any other questions, please do not hesitate to contact us via email or using the chat function. We are here to help!

Interested in kickstarting your next project?

Get the latest boilerplates, components, and news straight to your inbox.

By signing up, you agree to our Privacy Policy