@c15t/react 3.0.0-alpha.3 → 3.0.0-alpha.4

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 (183) hide show
  1. package/AGENTS.md +91 -72
  2. package/README.md +21 -17
  3. package/SKILL.md +34 -0
  4. package/dist/component-hooks/use-headless-consent-ui.js +1 -1
  5. package/dist/components/consent-gate/atoms.js +1 -1
  6. package/dist/components/consent-gate/consent-gate.js +1 -1
  7. package/dist/components/iab-panel/atoms/card.js +1 -1
  8. package/dist/components/iab-panel/atoms/feature-item.js +2 -0
  9. package/dist/components/iab-panel/atoms/header.js +1 -1
  10. package/dist/components/iab-panel/iab-panel.js +1 -1
  11. package/dist/components/iab-panel/index.js +1 -1
  12. package/dist/components/iab-prompt/atoms/overlay.js +1 -1
  13. package/dist/components/iab-prompt/atoms/root.js +1 -1
  14. package/dist/components/panel/atoms/card.js +1 -1
  15. package/dist/components/panel/atoms/root.js +1 -1
  16. package/dist/components/panel-trigger/atoms/button.js +1 -1
  17. package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
  18. package/dist/components/preferences/atoms/accordion.js +1 -1
  19. package/dist/components/prompt/atoms/overlay.js +1 -1
  20. package/dist/components/prompt/atoms/root.js +1 -1
  21. package/dist/components/prompt/components.js +1 -1
  22. package/dist/components/shared/libs/compose-refs.js +1 -0
  23. package/dist/components/shared/libs/slot.js +1 -1
  24. package/dist/components/shared/primitives/button.js +1 -1
  25. package/dist/components/shared/ui/dialog/dialog.js +1 -1
  26. package/dist/components/shared/ui/icon.js +1 -1
  27. package/dist/context/consent-tracking-context.js +1 -1
  28. package/dist/devtools.js +1 -1
  29. package/dist/draft.js +1 -1
  30. package/dist/hooks/use-focus-trap.js +1 -1
  31. package/dist/hooks.js +1 -1
  32. package/dist/iab/styles.tw3.css +4 -4
  33. package/dist/index.js +1 -1
  34. package/dist/module-hooks/iframe-blocker.js +1 -1
  35. package/dist/postcss-tailwind3.js +1 -0
  36. package/dist/provider.js +1 -1
  37. package/dist/server/fetch-ssr-data.js +1 -1
  38. package/dist/server/headers.js +1 -1
  39. package/dist/server/normalize-url.js +1 -1
  40. package/dist/styles.tw3.css +16 -16
  41. package/dist/transports/offline.js +1 -1
  42. package/dist/ui-save.js +1 -1
  43. package/dist/utils/merge-slot-props.js +1 -1
  44. package/dist/utils/theme-utils.js +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist-types/component-hooks/use-headless-consent-ui.d.ts +1 -1
  47. package/dist-types/components/iab-panel/atoms/feature-item.d.ts +28 -0
  48. package/dist-types/components/iab-panel/iab-panel.d.ts +2 -2
  49. package/dist-types/components/iab-panel/index.d.ts +5 -2
  50. package/dist-types/components/iab-panel/use-iab-translations.d.ts +4 -0
  51. package/dist-types/components/iab-prompt/iab-prompt.d.ts +2 -2
  52. package/dist-types/components/iab-prompt/index.d.ts +2 -2
  53. package/dist-types/components/panel/atoms/card.d.ts +1 -0
  54. package/dist-types/components/prompt/components.d.ts +6 -0
  55. package/dist-types/components/shared/libs/compose-refs.d.ts +20 -0
  56. package/dist-types/components/shared/ui/icon.d.ts +2 -1
  57. package/dist-types/context/consent-tracking-context.d.ts +10 -0
  58. package/dist-types/context/theme-context.d.ts +2 -2
  59. package/dist-types/context.d.ts +6 -0
  60. package/dist-types/devtools.d.ts +13 -2
  61. package/dist-types/draft.d.ts +10 -4
  62. package/dist-types/hooks/use-focus-trap.d.ts +3 -1
  63. package/dist-types/hooks.d.ts +54 -13
  64. package/dist-types/iab.d.ts +1 -1
  65. package/dist-types/index.d.ts +2 -2
  66. package/dist-types/postcss-tailwind3.d.ts +21 -0
  67. package/dist-types/provider.d.ts +22 -5
  68. package/dist-types/server/headers.d.ts +14 -4
  69. package/dist-types/server/normalize-url.d.ts +14 -7
  70. package/dist-types/server/types.d.ts +12 -1
  71. package/dist-types/transports/offline.d.ts +7 -16
  72. package/dist-types/ui-config-context.d.ts +7 -1
  73. package/dist-types/utils/merge-slot-props.d.ts +15 -1
  74. package/dist-types/utils/theme-utils.d.ts +17 -2
  75. package/dist-types/version.d.ts +1 -1
  76. package/docs/README.md +91 -72
  77. package/docs/assets/v3/bottom-bar.png +0 -0
  78. package/docs/assets/v3/brand-card.png +0 -0
  79. package/docs/assets/v3/brand-preferences.png +0 -0
  80. package/docs/assets/v3/choice-wall.png +0 -0
  81. package/docs/assets/v3/headless-bar-html.png +0 -0
  82. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  83. package/docs/assets/v3/headless-bar.png +0 -0
  84. package/docs/assets/v3/slim-bar.png +0 -0
  85. package/docs/concepts/choose-your-setup.md +87 -0
  86. package/docs/{frameworks/react/concepts → concepts}/consent-categories.md +22 -7
  87. package/docs/{guides → concepts}/consent-state.md +71 -101
  88. package/docs/{guides → concepts}/data-fetching.md +31 -27
  89. package/docs/concepts/how-consent-works.md +123 -0
  90. package/docs/{frameworks/react/concepts/policy-presets.md → concepts/policies.md} +7 -59
  91. package/docs/customization/class-names.md +202 -0
  92. package/docs/customization/dark-mode.md +157 -0
  93. package/docs/customization/motion.md +119 -0
  94. package/docs/customization/overview.md +67 -34
  95. package/docs/customization/recipes.md +839 -49
  96. package/docs/customization/slots.md +216 -35
  97. package/docs/customization/stylesheets.md +147 -0
  98. package/docs/customization/tailwind.md +842 -0
  99. package/docs/customization/tokens.md +163 -96
  100. package/docs/customization/translations.md +61 -3
  101. package/docs/frameworks/react/callbacks.md +118 -0
  102. package/docs/frameworks/react/clear-on-revocation.md +106 -0
  103. package/docs/frameworks/react/components/consent-banner.md +42 -28
  104. package/docs/frameworks/react/components/consent-dialog-link.md +13 -11
  105. package/docs/frameworks/react/components/consent-dialog-trigger.md +81 -76
  106. package/docs/frameworks/react/components/consent-dialog.md +56 -50
  107. package/docs/frameworks/react/components/consent-gate.md +37 -20
  108. package/docs/frameworks/react/components/consent-provider.md +126 -0
  109. package/docs/frameworks/react/components/consent-widget.md +23 -20
  110. package/docs/frameworks/react/components/dev-tools.md +52 -84
  111. package/docs/frameworks/react/components.md +105 -0
  112. package/docs/frameworks/react/compose.md +354 -0
  113. package/docs/frameworks/react/content-security-policy.md +126 -0
  114. package/docs/frameworks/react/customize.md +250 -0
  115. package/docs/frameworks/react/embeds.md +89 -0
  116. package/docs/frameworks/react/{hooks/overview.md → hooks.md} +21 -16
  117. package/docs/frameworks/react/{iab/overview.md → iab.md} +80 -31
  118. package/docs/frameworks/react/network-blocker.md +35 -41
  119. package/docs/frameworks/react/quickstart.md +139 -101
  120. package/docs/frameworks/react/rendering.md +128 -0
  121. package/docs/frameworks/react/scripts.md +115 -0
  122. package/docs/frameworks/react/translations.md +155 -0
  123. package/docs/frameworks/react/troubleshooting.md +92 -47
  124. package/docs/frameworks/react/vendor-consent.md +170 -0
  125. package/docs/guides/banner-experiments.md +654 -0
  126. package/docs/guides/troubleshooting.md +120 -47
  127. package/docs/guides/verify-consent.md +81 -49
  128. package/docs/integrations/adobe-analytics.md +167 -159
  129. package/docs/integrations/ahrefs-analytics.md +152 -154
  130. package/docs/integrations/amplitude.md +162 -156
  131. package/docs/integrations/building-integrations.md +136 -37
  132. package/docs/integrations/clearbit.md +154 -154
  133. package/docs/integrations/cloudflare-web-analytics.md +156 -156
  134. package/docs/integrations/cloudflare-zaraz.md +209 -261
  135. package/docs/integrations/crisp.md +164 -158
  136. package/docs/integrations/databuddy.md +157 -173
  137. package/docs/integrations/fathom-analytics.md +158 -156
  138. package/docs/integrations/front-chat.md +167 -167
  139. package/docs/integrations/google-maps.md +118 -83
  140. package/docs/integrations/google-tag-manager.md +178 -163
  141. package/docs/integrations/google-tag.md +163 -160
  142. package/docs/integrations/heap.md +163 -155
  143. package/docs/integrations/hightouch.md +161 -157
  144. package/docs/integrations/hotjar.md +159 -155
  145. package/docs/integrations/intercom.md +183 -153
  146. package/docs/integrations/klaviyo.md +486 -0
  147. package/docs/integrations/linkedin-insights.md +174 -150
  148. package/docs/integrations/logrocket.md +160 -156
  149. package/docs/integrations/matomo-analytics.md +188 -178
  150. package/docs/integrations/meta-pixel.md +188 -150
  151. package/docs/integrations/microsoft-clarity.md +163 -155
  152. package/docs/integrations/microsoft-uet.md +148 -154
  153. package/docs/integrations/mixpanel-analytics.md +155 -160
  154. package/docs/integrations/one-dollar-stats.md +166 -165
  155. package/docs/integrations/openai-pixel.md +204 -301
  156. package/docs/integrations/overview.md +137 -80
  157. package/docs/integrations/pinterest-tag.md +191 -183
  158. package/docs/integrations/pirsch.md +169 -159
  159. package/docs/integrations/plausible-analytics.md +172 -158
  160. package/docs/integrations/posthog.md +226 -241
  161. package/docs/integrations/promptwatch.md +154 -154
  162. package/docs/integrations/reddit-pixel.md +185 -157
  163. package/docs/integrations/rudderstack.md +201 -186
  164. package/docs/integrations/rybbit-analytics.md +171 -160
  165. package/docs/integrations/segment.md +182 -154
  166. package/docs/integrations/snapchat-pixel.md +186 -156
  167. package/docs/integrations/tiktok-pixel.md +171 -150
  168. package/docs/integrations/umami-analytics.md +163 -158
  169. package/docs/integrations/vercel-analytics.md +166 -157
  170. package/docs/integrations/x-pixel.md +176 -150
  171. package/docs/integrations/youtube.md +121 -86
  172. package/docs/upgrade-v3.md +475 -467
  173. package/package.json +15 -9
  174. package/docs/assets/v3/brand-bar.png +0 -0
  175. package/docs/assets/v3/mobile-card.png +0 -0
  176. package/docs/assets/v3/preferences.png +0 -0
  177. package/docs/frameworks/react/components/consent-manager-provider.md +0 -95
  178. package/docs/frameworks/react/script-loader.md +0 -69
  179. package/docs/frameworks/react/styling/overview.md +0 -266
  180. package/docs/guides/deployment-modes.md +0 -75
  181. package/docs/guides/shared-consent-controls.md +0 -158
  182. package/docs/integrations/clear-on-revocation.md +0 -167
  183. package/docs/integrations/granular-consent.md +0 -210
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c15t/react",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.4",
4
4
  "description": "React cookie banner, consent manager, preference center, and headless CMP components with IAB TCF and Consent Mode support.",
5
5
  "keywords": [
6
6
  "ccpa",
@@ -46,6 +46,7 @@
46
46
  "dist",
47
47
  "dist-types",
48
48
  "AGENTS.md",
49
+ "SKILL.md",
49
50
  "docs",
50
51
  "styles.css",
51
52
  "styles.tw3.css",
@@ -150,6 +151,11 @@
150
151
  "./styles.tw3.css": "./dist/styles.tw3.css",
151
152
  "./iab/styles.css": "./dist/iab/styles.css",
152
153
  "./iab/styles.tw3.css": "./dist/iab/styles.tw3.css",
154
+ "./postcss-tailwind3": {
155
+ "types": "./dist-types/postcss-tailwind3.d.ts",
156
+ "import": "./dist/postcss-tailwind3.js",
157
+ "default": "./dist/postcss-tailwind3.js"
158
+ },
153
159
  "./primitives": {
154
160
  "types": "./dist-types/primitives.d.ts",
155
161
  "import": "./dist/primitives.js",
@@ -243,20 +249,20 @@
243
249
  "test:watch": "bun prebuild && vitest"
244
250
  },
245
251
  "dependencies": {
246
- "@c15t/core": "3.0.0-alpha.3",
247
- "@c15t/dev-tools": "3.0.0-alpha.3",
248
- "@c15t/iab": "3.0.0-alpha.3",
249
- "@c15t/schema": "3.0.0-alpha.2",
250
- "@c15t/translations": "3.0.0-alpha.2",
251
- "@c15t/ui": "3.0.0-alpha.3",
252
+ "@c15t/core": "3.0.0-alpha.4",
253
+ "@c15t/dev-tools": "3.0.0-alpha.4",
254
+ "@c15t/iab": "3.0.0-alpha.4",
255
+ "@c15t/schema": "3.0.0-alpha.3",
256
+ "@c15t/translations": "3.0.0-alpha.4",
257
+ "@c15t/ui": "3.0.0-alpha.4",
252
258
  "@types/google.maps": "3.65.3"
253
259
  },
254
260
  "devDependencies": {
255
- "@c15t/backend": "3.0.0-alpha.3",
261
+ "@c15t/backend": "3.0.0-alpha.4",
256
262
  "@c15t/conformance": "0.0.1",
257
263
  "@c15t/typescript-config": "0.0.1",
258
264
  "@c15t/vitest-config": "1.0.0",
259
- "@iabtechlabtcf/core": "^1.5.20",
265
+ "@iabtechlabtcf/core": "^1.5.22",
260
266
  "genversion": "3.2.0",
261
267
  "msw": "^2.14.6",
262
268
  "typescript": "7.0.2"
Binary file
Binary file
Binary file
@@ -1,95 +0,0 @@
1
- ---
2
- title: ConsentProvider
3
- description: Configure the v3 consent runtime and share its state with child components.
4
- group: frameworks
5
- ---
6
-
7
- ## Mount one provider
8
-
9
- ```tsx
10
- import type { ReactNode } from 'react';
11
- import { ConsentProvider, ConsentBanner, ConsentDialog, ConsentDialogLink, hosted } from 'c15t/react';
12
-
13
- const mode = hosted({ url: 'https://your-project.inth.app' });
14
-
15
- export function Consent({ children }: { children: ReactNode }) {
16
- return (
17
- <ConsentProvider options={{ mode }}>
18
- {children}
19
- <ConsentBanner />
20
- <ConsentDialog />
21
- <ConsentDialogLink>Privacy settings</ConsentDialogLink>
22
- </ConsentProvider>
23
- );
24
- }
25
- ```
26
-
27
- Replace the URL with your Inth project endpoint. Import the adapter stylesheet
28
- once at the app root. In Next.js this component needs a client boundary; prefer
29
- the framework's `ConsentRoot` when passing server-resolved state.
30
-
31
- ## Provider responsibilities
32
-
33
- The provider owns initialization, persistence, configured script loading and
34
- subscriptions. Keep it mounted across client navigation. Its initial mode and
35
- prefetch configuration belong to the runtime's creation, not a per-render
36
- mechanism for switching visitors or backends.
37
-
38
- | Option | Purpose |
39
- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
40
- | `mode` | Hosted, offline or custom transport factory |
41
- | `scripts` | Consent-managed script configurations |
42
- | `callbacks` | Choice, permission and error events |
43
- | `theme`, `components` | Consent-action styles, theme slots and component slot attributes. Tokens render through `ConsentTheme` |
44
- | `presentation` | Prompt and preferences layout behavior |
45
- | `preloadDialog` | When the deferred `ConsentDialog` starts loading: `'idle'` (default) or `'intent'`; see [ConsentDialog](./consent-dialog.md#behavior) |
46
- | `i18n` | Languages and message overrides |
47
- | `storageConfig` | Browser record storage configuration |
48
- | `enabled` | Set false only when intentionally bypassing consent enforcement |
49
- | `reloadOnConsentRevoked` | Reload the page after the visitor turns off a granted category or vendor; defaults to `true` |
50
-
51
- `enabled: false` grants categories and allows gated loading while suppressing
52
- consent UI. It is not a way to fix failed initialization or hide a banner in
53
- production.
54
-
55
- ## Observe changes without inventing choices
56
-
57
- `onChoiceRecorded` reports explicit accept, reject and save actions.
58
- `onPermissionsChanged` also covers changes caused by policy, expiry or privacy
59
- signals. Hydration and notice dismissal do not become explicit choices.
60
-
61
- An externally owned runtime can be passed through `runtime`. Its owner must
62
- start and dispose it. A provider borrowing that runtime must not initialize or
63
- dispose a second copy. Passing a different `runtime` moves the provider and its
64
- hooks to the new runtime's kernel and unsubscribes them from the previous one.
65
- The previous runtime keeps running until its owner disposes it. Switch the
66
- provider to another runtime, or unmount it, before disposing the runtime it
67
- renders. Changing between a borrowed runtime and a provider-created one still
68
- requires remounting the provider. IAB actions taken before its handle is ready
69
- wait for that handle. If the provider unmounts or switches runtimes first, a
70
- pending `save()` rejects with an `AbortError` instead of waiting indefinitely.
71
- See [consent state](../../../guides/consent-state.md) and
72
- [deployment modes](../../../guides/deployment-modes.md).
73
-
74
- ## Reload after revocation
75
-
76
- Removing a script cannot stop code that already ran. A vendor's listeners,
77
- timers and widgets keep working until the page unloads. When an accept, reject
78
- or save turns off a category or vendor that was granted, the provider reloads
79
- the page once the save request settles, so the next page runs only permitted
80
- code. `onBeforeConsentRevocationReload` runs just before the reload. With a
81
- [`consentSource`](../../../guides/shared-consent-controls.md), any withdrawal the
82
- external CMP reports reloads the same way, including expiry.
83
-
84
- Otherwise, expiry, policy changes and privacy signals do not reload the page. Set
85
- `reloadOnConsentRevoked: false` only when every gated vendor stops itself on
86
- revocation, for example through its own opt-out API.
87
-
88
- ## Clear data when consent is denied
89
-
90
- Set `options.clearOnRevocation` to declare cookies, localStorage keys, and
91
- sessionStorage keys by optional consent category. Cleanup waits for policy
92
- resolution, then clears denied categories and later allowed-to-denied
93
- transitions. This option is initial-only. See
94
- [clear on revocation](../../../integrations/clear-on-revocation.md) for examples,
95
- cookie scopes, and browser limits.
@@ -1,69 +0,0 @@
1
- ---
2
- title: Load scripts with consent
3
- description: Register vendor scripts once and let effective permissions control loading.
4
- group: frameworks
5
- ---
6
-
7
- ## Register scripts on the provider
8
-
9
- Install `@c15t/scripts` for vendor helpers. This React-compatible client component
10
- uses Inth as the backend. Set the URL to the endpoint supplied by your Inth
11
- project and keep the component mounted around your application.
12
-
13
- ```tsx title="components/consent.tsx"
14
- 'use client';
15
-
16
- import type { ReactNode } from 'react';
17
- import { ConsentProvider, ConsentBanner, ConsentDialog, ConsentDialogLink, hosted } from 'c15t/react';
18
- import { metaPixel } from '@c15t/scripts/meta-pixel';
19
-
20
- const mode = hosted({ url: 'https://your-project.inth.app' });
21
- const scripts = [metaPixel({ pixelId: '123456789012345' })];
22
-
23
- export function Consent({ children }: { children: ReactNode }) {
24
- return (
25
- <ConsentProvider options={{ mode, scripts }}>
26
- {children}
27
- <ConsentBanner />
28
- <ConsentDialog />
29
- <ConsentDialogLink>Privacy settings</ConsentDialogLink>
30
- </ConsentProvider>
31
- );
32
- }
33
- ```
34
-
35
- Import your adapter's stylesheet globally, as in the framework quickstart. For
36
- an existing server-resolved `ConsentRoot`, keep that root and pass
37
- `scripts` as a top-level prop instead of mounting a second provider.
38
-
39
- ## Understand loading and revocation
40
-
41
- Ordinary scripts wait for their category's effective permission. Give each
42
- script a stable unique `id` and remove any other loader for the same vendor.
43
- Some helpers use `alwaysLoad` to load the SDK and signal consent through its own
44
- API. Read the vendor guide; a category field alone does not guarantee no
45
- requests.
46
-
47
- Removing a script element cannot undo JavaScript that already executed or
48
- requests already sent. Use the vendor's supported consent and cleanup behavior,
49
- and stop future event calls after revocation. Test both initial denial and a
50
- change from allowed to denied.
51
-
52
- Use [custom integrations](../../integrations/building-integrations.md) for an
53
- unlisted vendor and [verification](../../guides/verify-consent.md) for the network
54
- checks. Google helpers have a separate
55
- [Consent Mode contract](../../integrations/google-tag-manager.md).
56
-
57
- ## Clear stored tracking data
58
-
59
- Script gating does not remove cookies or Web Storage entries that a script
60
- already wrote. Add `clearOnRevocation` to `ConsentProvider.options` to remove
61
- declared data when its category is denied. See
62
- [clear on revocation](../../integrations/clear-on-revocation.md) for configuration
63
- and browser limits.
64
-
65
- ## Shared lifecycle controls
66
-
67
- See [shared consent controls](../../guides/shared-consent-controls.md) for external CMPs,
68
- preference delegation, withdrawal reloads, and application events. These controls
69
- use the same core runtime across frameworks.
@@ -1,266 +0,0 @@
1
- ---
2
- title: Styling
3
- description: Import the React stylesheet and theme c15t components with tokens,
4
- slots, and class names on ConsentProvider.
5
- group: frameworks
6
- ---
7
-
8
- ## Stylesheet
9
-
10
- Import the stylesheet once, next to your global CSS, in the entry module that
11
- renders `ConsentProvider`:
12
-
13
- ```tsx
14
- import 'c15t/react/styles.css';
15
- ```
16
-
17
- Every rule lives in `@layer components`, so unlayered utilities from Tailwind
18
- v4 and atomic classes from StyleX override it without specificity tricks.
19
- Tailwind v3 treats `@layer components` as its own directive, so import the
20
- Tailwind 3 build from your Tailwind entry instead, between the `components`
21
- and `utilities` directives:
22
-
23
- ```css
24
- @tailwind base;
25
- @tailwind components;
26
- @import 'c15t/react/styles.tw3.css';
27
- @tailwind utilities;
28
- ```
29
-
30
- ## Tokens
31
-
32
- Colors, radii, shadows, typography, and motion come from `--c15t-*` custom
33
- properties. The package stylesheet sets the default values. To change them,
34
- render `ConsentTheme` with your theme where your app renders on the server,
35
- or override the variables directly in your CSS.
36
-
37
- `ConsentTheme` renders a `<style id="c15t-theme">` element with the
38
- variables for `theme`. It is not a client component: rendered from a Server
39
- Component or another server-only file, the theme generator stays out of the
40
- browser bundle. Rendered from a client component it still works, but the
41
- browser downloads the generator (about 1.7 KB gzip). The provider no longer
42
- turns `theme` tokens into CSS. It still reads `consentActions` and slot
43
- styles from its `theme` option, and warns in development when `theme` holds
44
- tokens but the page has no `c15t-theme` stylesheet.
45
-
46
- | `ConsentTheme` prop | Purpose |
47
- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
48
- | `theme` | Colors, `dark` colors, typography, spacing, radius, shadows and motion. Defaults to the built-in theme. |
49
- | `colorScheme` | `'dark'` makes the dark tokens the default before hydration. `'system'` follows `prefers-color-scheme` with a CSS media query. Omit it to follow a `dark` or `c15t-dark` class on `<html>`. |
50
- | `nonce` | Content Security Policy nonce for the `<style>` element. |
51
-
52
- Pass the same `colorScheme` to `ConsentTheme` and to the provider. The
53
- provider keeps the `c15t-dark` class on `<html>` in sync after hydration.
54
- If your app manages dark mode through a root class, such as next-themes'
55
- `dark` class, omit `colorScheme` and include that class in the server
56
- HTML.
57
-
58
- To switch between light and dark at runtime, render `ConsentTheme` without
59
- `colorScheme` and toggle the `dark` class on `<html>`: its output already
60
- holds the variables for both schemes. To switch between different token
61
- sets, render `ConsentTheme` from a client component and change its props,
62
- which ships the generator.
63
-
64
- Outside React, call `generateThemeCSS(theme, colorScheme)` from
65
- `@c15t/ui/theme` on the server or at build time and put the result in a
66
- `<style>` element or your stylesheet. It escapes `<`, so the result is safe
67
- inside `<style>`.
68
-
69
- ```ts title="src/consent-theme.ts"
70
- import { defineTheme } from 'c15t/react';
71
-
72
- export const theme = defineTheme({
73
- colors: { primary: '#2f6f4e' },
74
- radius: { lg: '4px' },
75
- consentActions: {
76
- primary: { variant: 'primary', mode: 'filled' },
77
- dismiss: { variant: 'neutral', mode: 'stroke' },
78
- },
79
- });
80
- ```
81
-
82
- With server rendering, render `ConsentTheme` in the server-only part of your
83
- document, next to the provider. In a single-page app with no server render,
84
- either render it next to the provider, which ships the generator, or write the
85
- variables into your stylesheet. This partial example keeps the provider's
86
- `mode`, children and other options:
87
-
88
- ```tsx
89
- import { ConsentProvider, ConsentTheme } from 'c15t/react';
90
-
91
- import { theme } from './consent-theme';
92
-
93
- <>
94
- <ConsentTheme theme={theme} />
95
- <ConsentProvider options={{ mode, theme }}>{children}</ConsentProvider>
96
- </>;
97
- ```
98
-
99
- The provider's `theme` option only supplies `consentActions` and slot styles.
100
-
101
- Earlier v3 alphas generated theme CSS in the browser from the provider's
102
- `theme` option. To migrate:
103
-
104
- 1. Move the theme into a module without `'use client'`, so server and
105
- client files can both import it.
106
- 2. Render `<ConsentTheme theme={theme} />` next to the consent root, from a
107
- Server Component or another server-rendered file. Pass `colorScheme` and
108
- `nonce` if you set them on the provider.
109
- 3. Keep passing `theme` to the provider only for `consentActions` and slot
110
- styles. A theme with tokens only can be removed from the provider.
111
- 4. Keep the package stylesheet import. It carries the default tokens the
112
- provider used to inject.
113
-
114
- `consentActions` decides how each action role looks: `default` applies to
115
- every button, `primary` to whichever actions the policy or your props mark
116
- primary, and `accept`, `reject`, `customize`, and `dismiss` to one role each.
117
- Per-action keys win over `primary`, which wins over `default`.
118
-
119
- Banner sizing has its own variables. Override them in CSS when a variant
120
- needs a different footprint:
121
-
122
- | Variable | Default | Applies to |
123
- | ----------------------------------- | ------- | ---------------- |
124
- | `--consent-banner-max-width` | `440px` | `floating` cards |
125
- | `--consent-banner-widget-max-width` | `20rem` | `widget` chips |
126
- | `--consent-banner-wall-max-width` | `30rem` | `wall` cards |
127
-
128
- ## Colors by consent model
129
-
130
- The primary action can change while the brand color stays the same. Set
131
- `consentActions.primary` once, then select `primaryButton` per policy as
132
- shown in [ConsentBanner](../components/consent-banner.md#per-policy-buttons).
133
-
134
- To give opt-in and opt-out banners different colors, scope the tokens to
135
- the root's attributes. Include hover and foreground colors when overriding
136
- CSS tokens directly:
137
-
138
- ```css
139
- [data-prompt][data-model='opt-in'] {
140
- --c15t-primary: #2f6f4e;
141
- --c15t-primary-hover: #24563c;
142
- --c15t-text-on-primary: #fff;
143
- }
144
-
145
- [data-prompt][data-model='opt-out'] {
146
- --c15t-primary: #6b3fa0;
147
- --c15t-primary-hover: #55327f;
148
- --c15t-text-on-primary: #fff;
149
- }
150
- ```
151
-
152
- These colors apply to the action marked primary. Button layout and color
153
- changes do not change the policy or expire a saved choice.
154
-
155
- ## Slots
156
-
157
- Each component part is a slot. A slot accepts any attributes the element
158
- takes, so the contract is the same whether you write class strings or pass an
159
- object with `className` and `style`. Set slots on the provider under
160
- `components`, keyed by component and part.
161
-
162
- For a full-width notice, use the supported `bar` variant. Inside your existing
163
- provider, replace the stock banner with:
164
-
165
- ```tsx title="src/regional-banner.tsx"
166
- import { ConsentBanner, usePolicyRule } from 'c15t/react';
167
-
168
- export function RegionalBanner() {
169
- const policy = usePolicyRule();
170
- return <ConsentBanner variant={policy?.prompt === 'notice' ? 'bar' : 'floating'} />;
171
- }
172
- ```
173
-
174
- To remove the notice card's radius, add these values to the existing
175
- `options.components.banner` slots. The root owns `data-prompt`, so the card
176
- uses Tailwind's `group` selector to read it:
177
-
178
- ```ts
179
- const bannerSlots = {
180
- root: { className: 'group' },
181
- card: { className: 'group-data-[prompt=notice]:rounded-none' },
182
- rightLink: {
183
- className: 'underline-offset-4 data-[right=opt-out]:text-red-700',
184
- },
185
- };
186
-
187
- // In the existing options.components object:
188
- // banner: bannerSlots
189
- ```
190
-
191
- The root also carries `data-variant`, so you can restyle one shape without
192
- touching the others. Tailwind, giving a `bar` a brand-colored top edge and
193
- tighter text:
194
-
195
- ```tsx
196
- <ConsentProvider
197
- options={{
198
- mode,
199
- presentation: { prompt: { variant: 'bar' } },
200
- components: {
201
- banner: {
202
- root: { className: 'group' },
203
- card: {
204
- className:
205
- 'group-data-[variant=bar]:border-t-4 group-data-[variant=bar]:border-t-emerald-600',
206
- },
207
- },
208
- description: {
209
- banner: { className: 'group-data-[variant=bar]:text-xs' },
210
- },
211
- },
212
- }}
213
- />
214
- ```
215
-
216
- `data-variant` sits on the root, so child slots use Tailwind's `group`
217
- prefix to read it.
218
-
219
- StyleX, spreading the result of `stylex.props()` into a slot:
220
-
221
- ```tsx
222
- import * as stylex from '@stylexjs/stylex';
223
-
224
- const styles = stylex.create({
225
- card: { borderRadius: 0, boxShadow: 'none' },
226
- rightLink: { textUnderlineOffset: 4, color: 'rgb(185 28 28)' },
227
- });
228
-
229
- <ConsentProvider
230
- options={{
231
- mode,
232
- components: {
233
- banner: {
234
- card: stylex.props(styles.card),
235
- rightLink: stylex.props(styles.rightLink),
236
- },
237
- },
238
- }}
239
- />;
240
- ```
241
-
242
- Set `noStyle` on a component to drop the built-in classes from every part and
243
- keep only what your slots pass. Set `noStyle` in the provider options to do it
244
- for every component.
245
-
246
- Banner slot keys under `components.banner`:
247
-
248
- | Key | Element |
249
- | ------------- | ----------------------------------------------------------------------------------------------------------------- |
250
- | `root` | Fixed-position wrapper carrying `data-prompt`, `data-model`, `data-variant`, `data-position`, and `data-blocking` |
251
- | `cardShell` | Sizes the card and holds the branding tag |
252
- | `card` | The visible card, carrying `data-state` |
253
- | `header` | Title and description container |
254
- | `title` | Heading |
255
- | `footer` | Action area |
256
- | `actions` | Group of action groups |
257
- | `actionGroup` | One group of equally prominent actions |
258
- | `rights` | Group of right links, rendered before the actions |
259
- | `rightLink` | One right link, carrying `data-action="right"` and `data-right` |
260
- | `overlay` | Backdrop shown when the banner blocks the page |
261
-
262
- Action buttons carry `data-action` and `data-variant`, and right links carry
263
- `data-action="right"`, so a single rule such as `[data-action='dismiss']` or
264
- `[data-action='right']` styles one role across every surface. Right links are
265
- underlined text by default, so the only button on a notice is the primary
266
- action.
@@ -1,75 +0,0 @@
1
- ---
2
- title: Choose a deployment mode
3
- description: Choose who runs your consent backend, then select manifest, init or
4
- offline resolution for your deployment.
5
- group: guides
6
- ---
7
-
8
- ## Use Inth for managed policy and records
9
-
10
- Start with [Inth](https://inth.com) unless you need to operate the consent
11
- service yourself or deliberately need only local browser records. Configure
12
- policy rules and trusted origins in the project, then use its exact backend
13
- endpoint in your framework setup.
14
-
15
- | Backend ownership | Policy source | Record storage | Use when |
16
- | ------------------------- | ------------------------------------------------------ | ---------------------------------------- | ------------------------------------------------------------------------- |
17
- | Inth hosted service | Centrally managed policy through a manifest or `/init` | Browser records plus backend submissions | You want managed policy and consent records |
18
- | Self-hosted c15t | Your backend's manifest or `/init` | Browser records plus your database | You need to operate the service and its infrastructure |
19
- | Browser-only offline mode | Bundled `policyRules` | Browser persistence | Local development and tests. Not recommended for production environments. |
20
-
21
- Hosted and self-hosted c15t use the same transport protocol. Switching who runs
22
- the backend does not require switching from manifests to `/init`.
23
-
24
- ## Choose data fetching separately
25
-
26
- For Next.js deployments with a runtime server, use the
27
- [manifest setup](https://c15t.com/docs/frameworks/next/data-fetching). It reuses public policy data
28
- in your application while consent writes still go to Inth. Regular backend
29
- `/init` is available when you want backend-owned request resolution or a simpler
30
- browser setup. See [data fetching and transports](./data-fetching.md) for
31
- the comparison, including custom transports and offline mode.
32
-
33
- Manifest resolution removes the per-visitor `/init` request, and with it the
34
- backend's only count of visitors. The server adapters replace it with a session
35
- report: after each resolution, on a server-rendered page or the same-origin
36
- init route, the host posts a small report to the backend's `POST /sessions`,
37
- server-to-server and detached from the response. The browser makes no request
38
- and the report stores no identity; the visitor's IP and user agent travel as
39
- forwarded headers under the backend's usual IP handling. Each report is one
40
- resolution; a page view can produce a `render` and a `route` report, and the
41
- consuming side groups them into sessions by address and user agent within a
42
- window. Static output resolves in the browser and sends none. Set `reportSessions: false` on an adapter to turn
43
- it off.
44
-
45
- ## Match initialization to your application output
46
-
47
- | Application output | Initial state | Required setup |
48
- | ------------------ | ------------------------- | ----------------------------------------------------------- |
49
- | Request SSR | Prepared for this visitor | Adapter request helper and matching client configuration |
50
- | Static HTML or SPA | Resolved in the browser | Reachable external URLs or deliberately bundled local rules |
51
-
52
- Request SSR can include the visitor's prompt in the initial HTML. Pass the
53
- prepared records and policy resolution through to hydration. Do not convert
54
- effective permissions into new stored choices.
55
-
56
- Static HTML is shared across visitors. It cannot contain a choice resolved from
57
- each visitor's cookies or geography at build time. A static site can still use
58
- Inth through browser requests. A same-origin `/api/c15t` URL only works if a
59
- service actually serves it; a Next.js static export does not run API routes.
60
-
61
- A manifest contains reusable public policy data. A resolved init response and
62
- personalized consent HTML belong to a request. Do not give them the same shared
63
- cache treatment.
64
-
65
- ## Handle initialization and storage failures
66
-
67
- While no policy resolves, optional permissions stay denied and the stock
68
- consent UI stays hidden. No banner can mean pending or failed initialization.
69
- It does not mean permission to load analytics. Observe errors before changing
70
- presentation, and do not silently switch to offline policy after a hosted
71
- request fails.
72
-
73
- Browser storage can also be unavailable. A working in-memory interaction does
74
- not prove the choice survives reload. Use
75
- [verification](./verify-consent.md) to test the actual deployment.