@c15t/nextjs 2.0.0-rc.3 → 2.0.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/client/components/consent-dialog-link.js +3 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/libs/browser-initial-data.cjs +1 -0
  5. package/dist/libs/browser-initial-data.js +1 -0
  6. package/dist/libs/initial-data.cjs +1 -1
  7. package/dist/libs/initial-data.js +1 -1
  8. package/dist/version.cjs +1 -1
  9. package/dist/version.js +1 -1
  10. package/dist-types/headless.d.ts +1 -0
  11. package/{dist → dist-types}/index.d.ts +4 -3
  12. package/dist-types/libs/browser-initial-data.d.ts +9 -0
  13. package/{dist → dist-types}/libs/initial-data.d.ts +1 -2
  14. package/dist-types/types.d.ts +38 -0
  15. package/dist-types/version.d.ts +1 -0
  16. package/docs/README.md +73 -0
  17. package/docs/building-headless-components.md +250 -0
  18. package/docs/callbacks.md +117 -0
  19. package/docs/components/consent-banner.md +174 -0
  20. package/docs/components/consent-dialog-link.md +59 -0
  21. package/docs/components/consent-dialog-trigger.md +103 -0
  22. package/docs/components/consent-dialog.md +137 -0
  23. package/docs/components/consent-manager-provider.md +422 -0
  24. package/docs/components/consent-widget.md +78 -0
  25. package/docs/components/dev-tools.md +63 -0
  26. package/docs/components/frame.md +73 -0
  27. package/docs/concepts/client-modes.md +163 -0
  28. package/docs/concepts/consent-categories.md +97 -0
  29. package/docs/concepts/consent-models.md +116 -0
  30. package/docs/concepts/cookie-management.md +122 -0
  31. package/docs/concepts/glossary.md +23 -0
  32. package/docs/concepts/initialization-flow.md +141 -0
  33. package/docs/concepts/policy-packs.md +229 -0
  34. package/docs/headless.md +184 -0
  35. package/docs/hooks/use-color-scheme.md +40 -0
  36. package/docs/hooks/use-consent-manager/checking-consent.md +94 -0
  37. package/docs/hooks/use-consent-manager/location-info.md +95 -0
  38. package/docs/hooks/use-consent-manager/overview.md +390 -0
  39. package/docs/hooks/use-consent-manager/setting-consent.md +92 -0
  40. package/docs/hooks/use-draggable.md +57 -0
  41. package/docs/hooks/use-focus-trap.md +41 -0
  42. package/docs/hooks/use-reduced-motion.md +35 -0
  43. package/docs/hooks/use-ssr-status.md +31 -0
  44. package/docs/hooks/use-text-direction.md +49 -0
  45. package/docs/hooks/use-translations.md +116 -0
  46. package/docs/iab/consent-banner.md +95 -0
  47. package/docs/iab/consent-dialog.md +135 -0
  48. package/docs/iab/overview.md +119 -0
  49. package/docs/iab/use-gvl-data.md +208 -0
  50. package/docs/iframe-blocking.md +107 -0
  51. package/docs/integrations/databuddy.md +186 -0
  52. package/docs/integrations/google-tag-manager.md +153 -0
  53. package/docs/integrations/google-tag.md +149 -0
  54. package/docs/integrations/linkedin-insights.md +109 -0
  55. package/docs/integrations/meta-pixel.md +342 -0
  56. package/docs/integrations/microsoft-uet.md +112 -0
  57. package/docs/integrations/overview.md +89 -0
  58. package/docs/integrations/posthog.md +177 -0
  59. package/docs/integrations/tiktok-pixel.md +113 -0
  60. package/docs/integrations/x-pixel.md +143 -0
  61. package/docs/internationalization.md +197 -0
  62. package/docs/network-blocker.md +178 -0
  63. package/docs/optimization.md +156 -0
  64. package/docs/policy-packs.md +246 -0
  65. package/docs/quickstart.md +145 -0
  66. package/docs/script-loader.md +300 -0
  67. package/docs/server-side.md +171 -0
  68. package/docs/styling/classnames.md +84 -0
  69. package/docs/styling/color-scheme.md +82 -0
  70. package/docs/styling/css-variables.md +92 -0
  71. package/docs/styling/overview.md +312 -0
  72. package/docs/styling/slots.md +93 -0
  73. package/docs/styling/tailwind.md +86 -0
  74. package/docs/styling/tokens.md +214 -0
  75. package/docs/troubleshooting.md +146 -0
  76. package/package.json +20 -10
  77. package/dist/headless.d.ts +0 -2
  78. package/dist/headless.d.ts.map +0 -1
  79. package/dist/index.d.ts.map +0 -1
  80. package/dist/libs/initial-data.d.ts.map +0 -1
  81. package/dist/types.d.ts +0 -16
  82. package/dist/types.d.ts.map +0 -1
  83. package/dist/version.d.ts +0 -2
  84. package/dist/version.d.ts.map +0 -1
@@ -0,0 +1,422 @@
1
+ ---
2
+ title: ConsentManagerProvider
3
+ description: The root provider component that initializes the consent system and makes consent state available to all child components.
4
+ ---
5
+ `ConsentManagerProvider` is the root component for the c15t consent system. It initializes the consent store, detects the user's jurisdiction, resolves translations, and provides consent state to all child components via React context.
6
+
7
+ Every other c15t component and hook must be rendered inside this provider.
8
+
9
+ ## Basic Usage
10
+
11
+ ```tsx
12
+ import { type ReactNode } from 'react';
13
+ import { ConsentManagerProvider, ConsentBanner, ConsentDialog } from '@c15t/nextjs';
14
+
15
+ export default function ConsentManager({ children }: { children: ReactNode }) {
16
+ return (
17
+ <ConsentManagerProvider
18
+ options={{
19
+ mode: 'hosted',
20
+ backendURL: '/api/c15t',
21
+ consentCategories: ['necessary', 'measurement', 'marketing'],
22
+ }}
23
+ >
24
+ <ConsentBanner />
25
+ <ConsentDialog />
26
+ {children}
27
+ </ConsentManagerProvider>
28
+ );
29
+ }
30
+ ```
31
+
32
+ ## Options Reference
33
+
34
+ ### CommonInlineStoreOptions
35
+
36
+ |Property|Type|Description|Default|Required|
37
+ |:--|:--|:--|:--|:--:|
38
+ |enabled|boolean \|undefined|Whether c15t should be active.|true|Optional|
39
+ |callbacks|[Callbacks \|undefined](https://v2.c15t.com/docs/frameworks/react/callbacks)|Event callbacks for consent actions.|-|Optional|
40
+ |scripts|[Script \|undefined](https://v2.c15t.com/docs/frameworks/react/script-loader)|Dynamically load scripts based on consent state.|-|Optional|
41
+ |legalLinks|Object \|undefined|Configuration for the legal links.|-|Optional|
42
+ |storageConfig|StorageConfig \|undefined|Storage configuration for consent persistence.|-|Optional|
43
+ |user|User \|undefined|The user's information. Usually your own internal ID for the user from your auth provider.|-|Optional|
44
+ |overrides|Overrides \|undefined|Forcefully set values like country, region, language for the consent manager. These values will override the values detected from the browser.|-|Optional|
45
+ |networkBlocker|[NetworkBlockerConfig \|undefined](https://v2.c15t.com/docs/frameworks/react/network-blocker)|Configuration for the network request blocker.|-|Optional|
46
+ |iab|[IABConfig \|undefined](https://v2.c15t.com/docs/frameworks/react/iab/overview)|IAB TCF 2.3 configuration.|-|Optional|
47
+ |ssrData|[Object \|undefined](https://v2.c15t.com/docs/frameworks/react/server-side)|SSR-prefetched data for hydration.|-|Optional|
48
+
49
+ #### `callbacks` Callbacks
50
+
51
+ Event callbacks for consent actions.
52
+
53
+ |Property|Type|Description|Default|Required|
54
+ |:--|:--|:--|:--|:--:|
55
+ |onBannerFetched|Callback\<OnBannerFetchedPayload> \|undefined|Called when the consent banner is fetched.|-|Optional|
56
+ |onConsentSet|Callback\<OnConsentSetPayload> \|undefined|Called when the consent is set.|-|Optional|
57
+ |onError|Callback\<OnErrorPayload> \|undefined|Called when an error occurs.|-|Optional|
58
+ |onBeforeConsentRevocationReload|Callback\<OnConsentSetPayload> \|undefined|Called before the page reloads when consent is revoked.|-|Optional|
59
+
60
+ #### `scripts` Script
61
+
62
+ Dynamically load scripts based on consent state.
63
+
64
+ |Property|Type|Description|Default|Required|
65
+ |:--|:--|:--|:--|:--:|
66
+ |id|string|Unique identifier for the script|-|✅ Required|
67
+ |src|string \|undefined|URL of the script to load|-|Optional|
68
+ |textContent|string \|undefined|Inline JavaScript code to execute|-|Optional|
69
+ |category|HasCondition\<AllConsentNames>|Consent category or condition required to load this script|-|✅ Required|
70
+ |callbackOnly|boolean \|undefined|Whether this is a callback-only script that doesn't need to load an external resource. When true, no script tag will be added to the DOM, only callbacks will be executed.|-|Optional|
71
+ |persistAfterConsentRevoked|boolean \|undefined|Whether the script should persist after consent is revoked.|-|Optional|
72
+ |alwaysLoad|boolean \|undefined|Whether the script should always load regardless of consent state. This is useful for scripts like Google Tag Manager or PostHog that manage their own consent state internally. The script will load immediately and never be unloaded based on consent changes. Note: When using this option, you are responsible for ensuring the script itself respects user consent preferences through its own consent management.|-|Optional|
73
+ |fetchPriority|"high" \|"low" \|"auto" \|undefined|Priority hint for browser resource loading|-|Optional|
74
+ |attributes|Record\<string, string> \|undefined|Additional attributes to add to the script element|-|Optional|
75
+ |async|boolean \|undefined|Whether to use async loading|-|Optional|
76
+ |defer|boolean \|undefined|Whether to defer script loading|-|Optional|
77
+ |nonce|string \|undefined|Content Security Policy nonce|-|Optional|
78
+ |anonymizeId|boolean \|undefined|Whether to use an anonymized ID for the script element, this helps ensure the script is not blocked by ad blockers|-|Optional|
79
+ |target|"head" \|"body" \|undefined|Where to inject the script element in the DOM. Options: \`'head'\`: Scripts are appended to \`\<head>\` (default); \`'body'\`: Scripts are appended to \`\<body>\`|-|Optional|
80
+ |onBeforeLoad|((info: ScriptCallbackInfo) => void) \|undefined|Callback executed before the script is loaded|-|Optional|
81
+ |onLoad|((info: ScriptCallbackInfo) => void) \|undefined|Callback executed when the script loads successfully|-|Optional|
82
+ |onError|((info: ScriptCallbackInfo) => void) \|undefined|Callback executed if the script fails to load|-|Optional|
83
+ |onConsentChange|((info: ScriptCallbackInfo) => void) \|undefined|Callback executed whenever the consent store is changed. This callback only applies to scripts already loaded.|-|Optional|
84
+ |vendorId|string \|number \|undefined|IAB TCF vendor ID - links script to a registered vendor. When in IAB mode, the script will only load if this vendor has consent. Takes precedence over \`category\` when in IAB mode. Use custom vendor IDs (string or number) to gate non-IAB vendors too.|-|Optional|
85
+ |iabPurposes|number\[] \|undefined|IAB TCF purpose IDs this script requires consent for. When in IAB mode and no vendorId is set, the script will only load if ALL specified purposes have consent.|-|Optional|
86
+ |iabLegIntPurposes|number\[] \|undefined|IAB TCF legitimate interest purpose IDs. These purposes can operate under legitimate interest instead of consent. The script loads if all iabPurposes have consent OR all iabLegIntPurposes have legitimate interest established.|-|Optional|
87
+ |iabSpecialFeatures|number\[] \|undefined|IAB TCF special feature IDs this script requires. Options: 1: Use precise geolocation data; 2: Actively scan device characteristics for identification|-|Optional|
88
+
89
+ #### `legalLinks`
90
+
91
+ Configuration for the legal links.
92
+
93
+ |Property|Type|Description|Default|Required|
94
+ |:--|:--|:--|:--|:--:|
95
+ |privacyPolicy|LegalLink \|undefined|-|-|✅ Required|
96
+ |cookiePolicy|LegalLink \|undefined|-|-|✅ Required|
97
+ |termsOfService|LegalLink \|undefined|-|-|✅ Required|
98
+
99
+ #### `storageConfig` StorageConfig
100
+
101
+ Storage configuration for consent persistence.
102
+
103
+ |Property|Type|Description|Default|Required|
104
+ |:--|:--|:--|:--|:--:|
105
+ |storageKey|string \|undefined|Custom storage key for localStorage and cookies|-|Optional|
106
+ |crossSubdomain|boolean \|undefined|Enable cross-subdomain cookies by default|-|Optional|
107
+ |defaultDomain|string \|undefined|Custom default domain for cookies|-|Optional|
108
+ |defaultExpiryDays|number \|undefined|Default cookie expiration in days|-|Optional|
109
+
110
+ #### `user` User
111
+
112
+ The user's information. Usually your own internal ID for the user from your auth provider.
113
+
114
+ |Property|Type|Description|Default|Required|
115
+ |:--|:--|:--|:--|:--:|
116
+ |id|string|Usually your own internal ID for the user from your auth provider|-|✅ Required|
117
+ |identityProvider|string \|undefined|The identity provider of the user. Usually the name of the identity provider e.g. 'clerk', 'auth0', 'custom', etc.|-|Optional|
118
+
119
+ #### `overrides` Overrides
120
+
121
+ Forcefully set values like country, region, language for the consent manager. These values will override the values detected from the browser.
122
+
123
+ |Property|Type|Description|Default|Required|
124
+ |:--|:--|:--|:--|:--:|
125
+ |country|string \|undefined|Country code to forcefully set|-|Optional|
126
+ |region|string \|undefined|Region code to forcefully set|-|Optional|
127
+ |language|string \|undefined|Language code to forcefully set|-|Optional|
128
+ |gpc|boolean \|undefined|Override the Global Privacy Control (GPC) signal. When \`true\`, simulates GPC being active (opt-out of marketing/measurement). When \`false\`, suppresses the real browser GPC signal. When \`undefined\`, falls back to the browser's \`navigator.globalPrivacyControl\`.|-|Optional|
129
+
130
+ #### `networkBlocker` NetworkBlockerConfig
131
+
132
+ Configuration for the network request blocker.
133
+
134
+ |Property|Type|Description|Default|Required|
135
+ |:--|:--|:--|:--|:--:|
136
+ |enabled|boolean \|undefined|Whether the network blocker is enabled.|-|Optional|
137
+ |initialConsents|ConsentState \|undefined|The consent state snapshot that is currently used for blocking logic.|-|Optional|
138
+ |logBlockedRequests|boolean \|undefined|Whether to automatically log blocked requests to the console.|-|Optional|
139
+ |onRequestBlocked|((info: BlockedRequestInfo) => void) \|undefined|Callback invoked whenever a request is blocked.|-|Optional|
140
+ |rules|NetworkBlockerRule|Domain rules that determine which requests should be blocked.|-|✅ Required|
141
+
142
+ #### `iab` IABConfig
143
+
144
+ IAB TCF 2.3 configuration.
145
+
146
+ |Property|Type|Description|Default|Required|
147
+ |:--|:--|:--|:--|:--:|
148
+ |enabled|boolean|Enable IAB TCF 2.3 mode. Note: Only works in 'hosted' client mode (legacy alias: 'c15t') because it requires a backend. Options: Fetch GVL from gvl.consent.io; Initialize \_\_tcfapi CMP API; Generate TC Strings for IAB compliance|-|✅ Required|
149
+ |cmpId|number \|undefined|CMP ID registered with IAB Europe. When using consent.io as the backend, this is automatically provided via the \`/init\` endpoint — no client-side configuration needed. Only set this if you self-host and have your own CMP registration. A valid (non-zero) CMP ID is required for IAB TCF compliance.|-|Optional|
150
+ |cmpVersion|string \|number \|undefined|CMP version. When omitted, defaults to package version from \`\~/cmp-defaults\` (which uses \~/version).|-|Optional|
151
+ |vendors|number\[] \|undefined|IAB-registered vendor IDs to include (optional). Used to scope the vendor list when fetching GVL or when hosted fallback paths are used (e.g. if GVL fetch fails).|-|Optional|
152
+ |customVendors|NonIABVendor \|undefined|Custom vendors not registered with IAB. These are displayed separately in the consent UI with a note that they have different privacy practices than IAB vendors.|-|Optional|
153
+ |publisherCountryCode|string \|undefined|Publisher country code (2-letter ISO).|-|Optional|
154
+ |isServiceSpecific|boolean \|undefined|Whether consent is service-specific (not global).|-|Optional|
155
+ |gvl|Object \|undefined \|null|Pre-loaded Global Vendor List for testing or SSR. Options: Testing (avoids network calls and mocking complexity); SSR (use server-fetched GVL); Offline/air-gapped deployments|-|Optional|
156
+
157
+ #### `ssrData`
158
+
159
+ SSR-prefetched data for hydration.
160
+
161
+ |Property|Type|Description|Default|Required|
162
+ |:--|:--|:--|:--|:--:|
163
+ |init|Object \|undefined \|null|Init endpoint response with jurisdiction, location, translations, and optional GVL.|-|✅ Required|
164
+ |gvl|Object \|undefined \|null|Global Vendor List data for IAB TCF mode. Note: When init returns 200 without gvl, client IAB settings are overridden to disabled.|-|Optional|
165
+ |metadata|SSRInitRequestMetadata \|undefined|Optional metadata for debugging SSR transport behavior.|-|Optional|
166
+
167
+ ### ConsentManagerContentOptions
168
+
169
+ |Property|Type|Description|Default|Required|
170
+ |:--|:--|:--|:--|:--:|
171
+ |i18n|I18nConfig \|undefined|Preferred i18n configuration in c15t v2.|-|Optional|
172
+ |translations|[TranslationConfig \|undefined](https://v2.c15t.com/docs/frameworks/react/internationalization)|Translation configuration to seed the store with.|-|Optional|
173
+ |consentCategories|[AllConsentNames \|undefined](https://v2.c15t.com/docs/frameworks/react/concepts/consent-categories)|Consent categories to show in the consent banner.|-|Optional|
174
+
175
+ #### `i18n` I18nConfig
176
+
177
+ Preferred i18n configuration in c15t v2.
178
+
179
+ |Property|Type|Description|Default|Required|
180
+ |:--|:--|:--|:--|:--:|
181
+ |messages|Record\<string, Partial\<Translations>> \|undefined|Translation message map keyed by language code (\`en\`, \`de\`, \`fr\`, ...).|-|✅ Required|
182
+ |locale|string \|undefined|Preferred language code used as the initial fallback locale.|-|Optional|
183
+ |detectBrowserLanguage|boolean \|undefined|Whether to auto-detect from browser language settings.|-|Optional|
184
+
185
+ #### `translations` TranslationConfig
186
+
187
+ Translation configuration to seed the store with.
188
+
189
+ |Property|Type|Description|Default|Required|
190
+ |:--|:--|:--|:--|:--:|
191
+ |translations|Record\<string, Partial\<Translations>> \|undefined|-|-|✅ Required|
192
+ |defaultLanguage|string \|undefined|-|-|Optional|
193
+ |disableAutoLanguageSwitch|boolean \|undefined|-|-|Optional|
194
+
195
+ ### UIOptions
196
+
197
+ |Property|Type|Description|Default|Required|
198
+ |:--|:--|:--|:--|:--:|
199
+ |theme|[Theme \|undefined](https://v2.c15t.com/docs/frameworks/react/styling/tokens)|Visual theme to apply.|-|Optional|
200
+ |disableAnimation|boolean \|undefined|Whether to disable animations.|false|Optional|
201
+ |scrollLock|boolean \|undefined|Whether to lock scroll when dialogs are open.|false|Optional|
202
+ |trapFocus|boolean \|undefined|Whether to trap focus within dialogs.|true|Optional|
203
+ |colorScheme|["light" \|"dark" \|"system" \|undefined](https://v2.c15t.com/docs/frameworks/react/styling/color-scheme)|Color scheme preference. With this option, you can force the theme to be light, dark or system. Otherwise, the theme will be detected if you have '.dark' classname in your document.|-|Optional|
204
+ |noStyle|[boolean \|undefined](https://v2.c15t.com/docs/frameworks/react/headless)|Whether to disable default styles.|false|Optional|
205
+
206
+ #### `theme` Theme
207
+
208
+ Visual theme to apply.
209
+
210
+ |Property|Type|Description|Default|Required|
211
+ |:--|:--|:--|:--|:--:|
212
+ |colors|ColorTokens \|undefined|Color palette for light mode.|-|Optional|
213
+ |dark|ColorTokens \|undefined|Dark mode color overrides.|-|Optional|
214
+ |typography|TypographyTokens \|undefined|Typography settings for text elements.|-|Optional|
215
+ |spacing|SpacingTokens \|undefined|Spacing scale for internal padding and margins.|-|Optional|
216
+ |radius|RadiusTokens \|undefined|Border radius scale for rounded corners.|-|Optional|
217
+ |shadows|ShadowTokens \|undefined|Box shadow scale for depth and elevation.|-|Optional|
218
+ |motion|MotionTokens \|undefined|Animation and transition timing.|-|Optional|
219
+ |consentActions|Object \|undefined|Semantic button styling for consent actions.|-|Optional|
220
+ |slots|ComponentSlots \|undefined|Component-specific style overrides.|-|Optional|
221
+
222
+ ## Mode: hosted vs offline
223
+
224
+ ```tsx
225
+ // Hosted mode — persists to hosted backend
226
+ <ConsentManagerProvider
227
+ options={{
228
+ mode: 'hosted',
229
+ backendURL: '/api/c15t',
230
+ }}
231
+ >
232
+
233
+ // Offline mode — local cookie storage only
234
+ <ConsentManagerProvider
235
+ options={{
236
+ mode: 'offline',
237
+ }}
238
+ >
239
+ ```
240
+
241
+ See [Client Modes](/docs/frameworks/next/concepts/client-modes) for a detailed comparison.
242
+
243
+ ## Legal Links
244
+
245
+ `legalLinks` defines the URLs shown in consent UI text (banner, dialog, and widget where applicable).
246
+ Configure only the links you want to expose.
247
+
248
+ ```tsx
249
+ <ConsentManagerProvider
250
+ options={{
251
+ backendURL: 'https://your-instance.c15t.dev',
252
+ legalLinks: {
253
+ privacyPolicy: {
254
+ href: '/privacy',
255
+ target: '_self',
256
+ },
257
+ cookiePolicy: {
258
+ href: '/cookies',
259
+ target: '_self',
260
+ },
261
+ termsOfService: {
262
+ href: 'https://example.com/terms',
263
+ target: '_blank',
264
+ rel: 'noopener noreferrer',
265
+ label: 'Terms of Service',
266
+ },
267
+ },
268
+ }}
269
+ >
270
+ ```
271
+
272
+ Notes:
273
+
274
+ * Omitting a key (for example `termsOfService`) hides that link.
275
+ * `label` overrides the translated text for that single link.
276
+ * Use `_self` for internal pages and `_blank` + `rel="noopener noreferrer"` for external pages.
277
+ * Control which of the configured links render in each component via the component's `legalLinks` prop.
278
+
279
+ ## Overrides
280
+
281
+ `overrides` lets you force location/language signals instead of browser or network detection.
282
+ This is useful for QA, local development, and preview environments.
283
+
284
+ ```tsx
285
+ <ConsentManagerProvider
286
+ options={{
287
+ backendURL: 'https://your-instance.c15t.dev',
288
+ overrides: {
289
+ country: 'DE',
290
+ region: 'BY',
291
+ language: 'de-DE',
292
+ },
293
+ }}
294
+ >
295
+ ```
296
+
297
+ You can also override Global Privacy Control (GPC) behavior during testing:
298
+
299
+ ```tsx
300
+ <ConsentManagerProvider
301
+ options={{
302
+ backendURL: 'https://your-instance.c15t.dev',
303
+ overrides: {
304
+ gpc: true,
305
+ },
306
+ }}
307
+ >
308
+ ```
309
+
310
+ > ⚠️ **Warning:**
311
+ > Treat overrides as an environment/testing tool. Avoid hard-coding production overrides unless that behavior is intentional for your deployment.
312
+
313
+ ## Policy Packs
314
+
315
+ In hosted mode (recommended), the backend resolves the correct policy automatically — no frontend policy config needed:
316
+
317
+ ```tsx
318
+ <ConsentManagerProvider
319
+ options={{
320
+ backendURL: 'https://your-instance.c15t.dev',
321
+ }}
322
+ >
323
+ ```
324
+
325
+ ### Fallback: Offline Policies
326
+
327
+ When no backend is available, `ConsentManagerProvider` accepts `offlinePolicy.policyPacks` for local policy resolution:
328
+
329
+ ```tsx
330
+ <ConsentManagerProvider
331
+ options={{
332
+ mode: 'offline',
333
+ offlinePolicy: {
334
+ i18n: {
335
+ defaultProfile: 'default',
336
+ messages: {
337
+ default: {
338
+ translations: {
339
+ en: { cookieBanner: { title: 'Privacy choices' } },
340
+ },
341
+ },
342
+ qc: {
343
+ fallbackLanguage: 'fr',
344
+ translations: {
345
+ en: { cookieBanner: { title: 'Quebec Privacy Settings' } },
346
+ fr: { cookieBanner: { title: 'Paramètres de confidentialité du Québec' } },
347
+ },
348
+ },
349
+ },
350
+ },
351
+ policyPacks: [
352
+ {
353
+ id: 'qc_opt_in',
354
+ match: { regions: [{ country: 'CA', region: 'QC' }] },
355
+ i18n: { messageProfile: 'qc' },
356
+ consent: { model: 'opt-in', expiryDays: 365 },
357
+ ui: { mode: 'banner' },
358
+ },
359
+ {
360
+ id: 'default_world',
361
+ match: { isDefault: true },
362
+ consent: { model: 'none' },
363
+ ui: { mode: 'none' },
364
+ },
365
+ ],
366
+ },
367
+ overrides: {
368
+ country: 'CA',
369
+ region: 'QC',
370
+ },
371
+ }}
372
+ >
373
+ ```
374
+
375
+ Notes:
376
+
377
+ * `offlinePolicy` is only used in `offline` mode.
378
+ * `offlinePolicy.i18n` lets offline mode mirror hosted `messageProfile` and profile-local `fallbackLanguage` behavior.
379
+ * Omitting `offlinePolicy.policyPacks` uses the built-in synthetic opt-in fallback banner. Hosted network fallback uses the same opt-in banner.
380
+ * `offlinePolicy: { policyPacks: [] }` is explicit no-banner mode.
381
+ * In hosted mode, backend `policyPacks` remain the source of truth — frontend offline policies never override a live backend decision.
382
+
383
+ Read the full guide at [Policy Packs](/docs/frameworks/react/policy-packs) and the conceptual model at [Policy Packs Concept](/docs/frameworks/react/concepts/policy-packs).
384
+
385
+ ## Props
386
+
387
+ ### ConsentManagerProviderProps
388
+
389
+ |Property|Type|Description|Default|Required|
390
+ |:--|:--|:--|:--|:--:|
391
+ |children|ReactNode|React children to render within the provider.|-|✅ Required|
392
+ |options|[ConsentManagerOptions](https://v2.c15t.com/docs/frameworks/react/components/consent-manager-provider)|Configuration options for the consent manager. This includes core, React, store, and translation settings.|-|✅ Required|
393
+
394
+ #### `options` ConsentManagerOptions
395
+
396
+ Configuration options for the consent manager. This includes core, React, store, and translation settings.
397
+
398
+ |Property|Type|Description|Default|Required|
399
+ |:--|:--|:--|:--|:--:|
400
+ |store|StoreOptions \|undefined|-|-|Optional|
401
+ |offlinePolicy|OfflinePolicyConfig \|undefined|Top-level offline policy configuration.|-|Optional|
402
+ |storageConfig|StorageConfig \|undefined|Storage configuration for consent persistence|-|Optional|
403
+ |mode|"c15t" \|"custom" \|"hosted" \|"offline" \|undefined|Operating mode - custom endpoint implementation|-|Optional|
404
+ |backendURL|string \|undefined|Backend URL is not used in custom mode|-|Optional|
405
+ |enabled|boolean \|undefined|Whether c15t should be active.|-|Optional|
406
+ |callbacks|Callbacks \|undefined|Event callbacks for consent actions.|-|Optional|
407
+ |scripts|Script \|undefined|Dynamically load scripts based on consent state.|-|Optional|
408
+ |legalLinks|Partial\<Record\<keyof LegalLinksTranslations, LegalLink>> \|undefined|Configuration for the legal links.|-|Optional|
409
+ |user|User \|undefined|The user's information. Usually your own internal ID for the user from your auth provider.|-|Optional|
410
+ |overrides|Overrides \|undefined|Forcefully set values like country, region, language for the consent manager. These values will override the values detected from the browser.|-|Optional|
411
+ |networkBlocker|NetworkBlockerConfig \|undefined|Configuration for the network request blocker.|-|Optional|
412
+ |iab|IABConfig \|undefined|IAB TCF 2.3 configuration.|-|Optional|
413
+ |ssrData|Promise\<SSRInitialData \|undefined> \|undefined|SSR-prefetched data for hydration.|-|Optional|
414
+ |theme|Theme \|undefined|Visual theme to apply.|-|Optional|
415
+ |disableAnimation|boolean \|undefined|Whether to disable animations.|-|Optional|
416
+ |scrollLock|boolean \|undefined|Whether to lock scroll when dialogs are open.|-|Optional|
417
+ |trapFocus|boolean \|undefined|Whether to trap focus within dialogs.|-|Optional|
418
+ |colorScheme|"light" \|"dark" \|"system" \|undefined|Color scheme preference. With this option, you can force the theme to be light, dark or system. Otherwise, the theme will be detected if you have '.dark' classname in your document.|-|Optional|
419
+ |noStyle|boolean \|undefined|Whether to disable default styles.|-|Optional|
420
+ |i18n|I18nConfig \|undefined|Preferred i18n configuration in c15t v2.|-|Optional|
421
+ |translations|TranslationConfig \|undefined|Translation configuration to seed the store with.|-|Optional|
422
+ |consentCategories|AllConsentNames \|undefined|Consent categories to show in the consent banner.|-|Optional|
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: ConsentWidget
3
+ description: An inline consent management widget for embedding in settings or privacy pages. Shows category toggles with accordion layout.
4
+ ---
5
+ `ConsentWidget` is a standalone, inline consent management widget. Unlike `ConsentDialog` (which is a modal), the widget embeds directly in your page layout - ideal for privacy settings pages, account preferences, or any page where users should be able to manage consent without a modal overlay.
6
+
7
+ ## Basic Usage
8
+
9
+ ```tsx
10
+ import { ConsentWidget } from '@c15t/nextjs';
11
+
12
+ export function PrivacySettingsPage() {
13
+ return (
14
+ <>
15
+ <h1>Privacy Settings</h1>
16
+ <p>Manage your cookie preferences below.</p>
17
+ <ConsentWidget />
18
+ </>
19
+ );
20
+ }
21
+ ```
22
+
23
+ ## Configuration
24
+
25
+ ```tsx
26
+ <ConsentWidget
27
+ hideBranding
28
+ legalLinks={['privacyPolicy', 'cookiePolicy']}
29
+ noStyle={false}
30
+ disableAnimation={false}
31
+ />
32
+ ```
33
+
34
+ ## Accordion Behavior
35
+
36
+ Each consent category is rendered as an expandable accordion item. Clicking the category header expands it to show a description and any associated services. Users can toggle individual categories on or off using the switch control. The `necessary` category is always enabled and cannot be toggled.
37
+
38
+ ## Compound Components
39
+
40
+ Build fully custom widget layouts using sub-components:
41
+
42
+ ```tsx
43
+ <ConsentWidget.Root>
44
+ <ConsentWidget.Accordion type="multiple">
45
+ <ConsentWidget.AccordionItems />
46
+ </ConsentWidget.Accordion>
47
+ <ConsentWidget.Footer>
48
+ <ConsentWidget.FooterSubGroup>
49
+ <ConsentWidget.RejectButton />
50
+ <ConsentWidget.AcceptAllButton />
51
+ </ConsentWidget.FooterSubGroup>
52
+ <ConsentWidget.SaveButton />
53
+ </ConsentWidget.Footer>
54
+ </ConsentWidget.Root>
55
+ ```
56
+
57
+ * `ConsentWidget.Root` — Theme context provider
58
+ * `ConsentWidget.Accordion` — Radix-based accordion root
59
+ * `ConsentWidget.AccordionItems` — Auto-generates toggle items from consent config
60
+ * `ConsentWidget.AccordionItem` — Individual category item
61
+ * `ConsentWidget.AccordionTrigger` — Clickable header for each item
62
+ * `ConsentWidget.AccordionContent` — Collapsible content area
63
+ * `ConsentWidget.AccordionArrow` — Expand/collapse indicator
64
+ * `ConsentWidget.Switch` — Category toggle switch
65
+ * `ConsentWidget.Footer` — Footer container
66
+ * `ConsentWidget.FooterSubGroup` — Groups related buttons
67
+ * `ConsentWidget.AcceptAllButton` — Accepts all consent
68
+ * `ConsentWidget.RejectButton` — Rejects all consent
69
+ * `ConsentWidget.SaveButton` — Saves custom selections
70
+
71
+ ## Props
72
+
73
+ ### ConsentWidgetProps
74
+
75
+ |Property|Type|Description|Default|Required|
76
+ |:--|:--|:--|:--|:--:|
77
+ |hideBranding|boolean \|undefined|Controls whether to hide the branding in the widget footer.|-|Optional|
78
+ |legalLinks|(keyof LegalLinksTranslations)\[] \|null \|undefined|Controls which legal links to display in the widget footer.|-|Optional|
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: DevTools
3
+ description: A development tool for inspecting consent state, geolocation, loaded scripts, and consent events in real time.
4
+ ---
5
+ `DevTools` is a floating panel that shows the internal state of the consent manager. Use it during development to inspect consent values, geolocation results, loaded scripts, and debug consent flows. Also exported as `C15TDevTools` if you need to avoid naming conflicts with other devtools.
6
+
7
+ > ℹ️ **Info:**
8
+ > DevTools should only be included in development builds. The component renders nothing to the React tree - it injects directly into document.body.
9
+
10
+ ## Installation
11
+
12
+ DevTools lives in a separate package to keep it out of production bundles:
13
+
14
+ ```bash
15
+ bun add -D @c15t/dev-tools
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { type ReactNode } from 'react';
22
+ import { ConsentManagerProvider } from '@c15t/nextjs';
23
+ import { DevTools } from '@c15t/dev-tools/react';
24
+
25
+ export function ConsentManager({ children }: { children: ReactNode }) {
26
+ return (
27
+ <ConsentManagerProvider options={{ mode: 'hosted', backendURL: '/api/c15t' }}>
28
+ {children}
29
+ {process.env.NODE_ENV === 'development' && <DevTools />}
30
+ </ConsentManagerProvider>
31
+ );
32
+ }
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ ```tsx
38
+ <DevTools
39
+ position="bottom-right" // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
40
+ defaultOpen={false} // Start with panel open
41
+ namespace="c15tStore" // Store namespace to connect to
42
+ disabled={false} // Disable without removing from tree
43
+ />
44
+ ```
45
+
46
+ ## Panels
47
+
48
+ |Panel|What it shows|
49
+ |--|--|
50
+ |**Consents**|Current consent state for all categories|
51
+ |**Location**|Detected jurisdiction, country, region, and consent model|
52
+ |**Scripts**|Configured scripts and their load status|
53
+ |**IAB**|IAB TCF state (when enabled) - TC string, vendor consents, purposes|
54
+ |**Events**|Timeline of consent events and state changes|
55
+ |**Actions**|Buttons to trigger consent actions (accept all, reject all, reset)|
56
+
57
+ ## Props
58
+
59
+ ### C15TDevToolsProps
60
+
61
+ |Property|Type|Description|Default|Required|
62
+ |:--|:--|:--|:--|:--:|
63
+ |disabled|boolean \|undefined|Whether the DevTools should be disabled Useful for production builds|false|Optional|
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: Frame
3
+ description: A consent-gated content wrapper - children only mount when the required consent category is granted.
4
+ ---
5
+ `Frame` conditionally renders its children based on consent state. When consent for the specified category is not granted, a placeholder is shown instead. Children are not mounted at all until consent is given, preventing any network requests or script execution.
6
+
7
+ ## Basic Usage
8
+
9
+ ```tsx
10
+ import { Frame } from '@c15t/nextjs';
11
+
12
+ function YouTubeEmbed() {
13
+ return (
14
+ <Frame category="marketing">
15
+ <iframe
16
+ src="https://www.youtube.com/embed/dQw4w9WgXcQ"
17
+ width="560"
18
+ height="315"
19
+ allowFullScreen
20
+ />
21
+ </Frame>
22
+ );
23
+ }
24
+ ```
25
+
26
+ ## Custom Placeholder
27
+
28
+ Replace the default placeholder:
29
+
30
+ ```tsx
31
+ <Frame
32
+ category="experience"
33
+ placeholder={
34
+ <div className="rounded-lg border p-8 text-center">
35
+ <p>This content requires experience cookies.</p>
36
+ <p>Please enable them in your privacy settings.</p>
37
+ </div>
38
+ }
39
+ >
40
+ <InteractiveWidget />
41
+ </Frame>
42
+ ```
43
+
44
+ ## Compound Components
45
+
46
+ Build fully custom placeholder layouts:
47
+
48
+ ```tsx
49
+ <Frame.Root category="marketing">
50
+ <Frame.Title category="marketing" />
51
+ <Frame.Button category="marketing" />
52
+ </Frame.Root>
53
+ ```
54
+
55
+ * `Frame.Root` - Container with default placeholder styling
56
+ * `Frame.Title` - Displays a consent-request message with the category name
57
+ * `Frame.Button` - Button that opens the consent dialog for the specified category
58
+
59
+ ## Automatic Category Registration
60
+
61
+ When `Frame` mounts, it automatically adds its `category` to the active `consentCategories` list. This means you don't need to explicitly list the category in your provider's `consentCategories` option - if a `Frame` component uses it, it will be registered.
62
+
63
+ ## Props
64
+
65
+ ### FrameProps
66
+
67
+ |Property|Type|Description|Default|Required|
68
+ |:--|:--|:--|:--|:--:|
69
+ |children|ReactNode|Content rendered when consent is granted. Children are not mounted until consent is given, preventing unnecessary network requests.|-|✅ Required|
70
+ |category|AllConsentNames|Consent category required to render children.|-|✅ Required|
71
+ |placeholder|ReactNode|A custom placeholder component to display when consent is not met. If not provided, a default placeholder will be displayed.|-|Optional|
72
+ |noStyle|boolean \|undefined|When true, removes all default styling from the component|false|Optional|
73
+ |theme|any|Custom theme to override default styles while maintaining structure and accessibility. Merges with defaults. Ignored when \`noStyle=\{true}\`.|undefined|Optional|