@c15t/react 3.0.0-alpha.1 → 3.0.0-alpha.11

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 (413) hide show
  1. package/AGENTS.md +97 -70
  2. package/README.md +21 -17
  3. package/SKILL.md +34 -0
  4. package/dist/aggregate-components.js +1 -1
  5. package/dist/chunk-warming.js +1 -1
  6. package/dist/component-hooks/use-headless-consent-ui.js +1 -1
  7. package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
  8. package/dist/component-hooks/use-panel-trigger.js +1 -1
  9. package/dist/components/consent-gate/atoms.js +1 -0
  10. package/dist/components/consent-gate/consent-gate.js +2 -0
  11. package/dist/components/consent-gate/frame.js +2 -0
  12. package/dist/components/consent-gate/index.js +2 -0
  13. package/dist/components/consent-preferences-link/consent-preferences-link.js +1 -1
  14. package/dist/components/iab-panel/atoms/card.js +1 -1
  15. package/dist/components/iab-panel/atoms/feature-item.js +2 -0
  16. package/dist/components/iab-panel/atoms/header.js +1 -1
  17. package/dist/components/iab-panel/atoms/purpose-item.js +1 -1
  18. package/dist/components/iab-panel/atoms/root.js +1 -1
  19. package/dist/components/iab-panel/atoms/stack-item.js +1 -1
  20. package/dist/components/iab-panel/atoms/vendor-list.js +1 -1
  21. package/dist/components/iab-panel/hooks/use-gvl-data.js +1 -1
  22. package/dist/components/iab-panel/iab-panel.js +1 -1
  23. package/dist/components/iab-panel/index.js +1 -1
  24. package/dist/components/iab-prompt/atoms/overlay.js +1 -1
  25. package/dist/components/iab-prompt/atoms/root.js +1 -1
  26. package/dist/components/iab-prompt/iab-prompt.js +1 -1
  27. package/dist/components/panel/atoms/card.js +1 -1
  28. package/dist/components/panel/atoms/overlay.js +1 -1
  29. package/dist/components/panel/atoms/root.js +1 -1
  30. package/dist/components/panel/panel.js +1 -1
  31. package/dist/components/panel-trigger/atoms/button.js +1 -1
  32. package/dist/components/panel-trigger/atoms/icon.js +1 -1
  33. package/dist/components/panel-trigger/atoms/root.js +1 -1
  34. package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
  35. package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -0
  36. package/dist/components/panel-trigger/panel-trigger-toolbar.js +1 -1
  37. package/dist/components/panel-trigger/panel-trigger.js +1 -1
  38. package/dist/components/panel-trigger/toolbar-loader.js +2 -0
  39. package/dist/components/preferences/atoms/accordion.js +1 -1
  40. package/dist/components/preferences/atoms/root.js +1 -1
  41. package/dist/components/preferences/atoms/vendor-list.js +1 -0
  42. package/dist/components/preferences/index.js +1 -1
  43. package/dist/components/prompt/atoms/early-tap-script.js +2 -0
  44. package/dist/components/prompt/atoms/overlay.js +1 -1
  45. package/dist/components/prompt/atoms/root.js +1 -1
  46. package/dist/components/prompt/components.js +1 -1
  47. package/dist/components/prompt/policy-actions.js +1 -1
  48. package/dist/components/prompt/prompt.js +1 -1
  49. package/dist/components/shared/dialog-sheets.js +1 -0
  50. package/dist/components/shared/first-paint-sheets.js +1 -0
  51. package/dist/components/shared/iab-dialog-sheets.js +1 -0
  52. package/dist/components/shared/iab-first-paint-sheets.js +1 -0
  53. package/dist/components/shared/libs/compose-refs.js +1 -0
  54. package/dist/components/shared/libs/slot.js +1 -1
  55. package/dist/components/shared/primitives/button.js +1 -1
  56. package/dist/components/shared/primitives/legal-links/index.js +1 -1
  57. package/dist/components/shared/streamed-surface.js +2 -0
  58. package/dist/components/shared/surface-styles.js +2 -0
  59. package/dist/components/shared/ui/dialog/dialog.js +1 -1
  60. package/dist/components/shared/ui/icon.js +1 -1
  61. package/dist/components/shared/ui/logo.js +1 -1
  62. package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
  63. package/dist/consent-gate.js +2 -0
  64. package/dist/consent-theme.js +1 -0
  65. package/dist/context/consent-tracking-context.js +1 -1
  66. package/dist/context/index.js +1 -1
  67. package/dist/context.js +1 -1
  68. package/dist/devtools-launcher.js +2 -0
  69. package/dist/devtools.js +1 -1
  70. package/dist/draft-context.js +2 -0
  71. package/dist/draft.js +1 -1
  72. package/dist/external-iab-context.js +1 -1
  73. package/dist/gpp.js +2 -0
  74. package/dist/headless.js +1 -1
  75. package/dist/hooks/use-color-scheme.js +1 -1
  76. package/dist/hooks/use-committed-ref.js +2 -0
  77. package/dist/hooks/use-focus-trap.js +1 -1
  78. package/dist/hooks/use-headless-iab-consent-ui.js +1 -1
  79. package/dist/hooks/use-iab-policy-guard.js +1 -0
  80. package/dist/hooks/use-late-entry.js +2 -0
  81. package/dist/hooks.js +1 -1
  82. package/dist/iab/styles.tw3.css +5 -45
  83. package/dist/iab-context.js +1 -1
  84. package/dist/iab-dialog-deferred.js +2 -0
  85. package/dist/iab.js +1 -1
  86. package/dist/index-parts/consent-banner.js +1 -0
  87. package/dist/index-parts/consent-dialog-link.js +1 -0
  88. package/dist/index-parts/consent-dialog-trigger.js +1 -0
  89. package/dist/index-parts/consent-dialog.js +1 -0
  90. package/dist/index-parts/consent-gate.js +1 -0
  91. package/dist/index-parts/core.js +1 -0
  92. package/dist/index-parts/draft.js +1 -0
  93. package/dist/index-parts/frame.js +1 -0
  94. package/dist/index-parts/hooks.js +1 -0
  95. package/dist/index-parts/hosted.js +1 -0
  96. package/dist/index-parts/module-hooks.js +1 -0
  97. package/dist/index-parts/offline.js +1 -0
  98. package/dist/index-parts/presets.js +1 -0
  99. package/dist/index-parts/provider.js +1 -0
  100. package/dist/index-parts/theme.js +1 -0
  101. package/dist/index-parts/translations.js +1 -0
  102. package/dist/index.js +1 -1
  103. package/dist/kernel-selector.js +1 -0
  104. package/dist/modes.js +1 -0
  105. package/dist/module-hooks/iframe-blocker.js +1 -1
  106. package/dist/module-hooks/network-blocker.js +1 -1
  107. package/dist/module-hooks/network-hold.js +2 -0
  108. package/dist/module-hooks/persistence.js +1 -1
  109. package/dist/panel-link.js +1 -1
  110. package/dist/panel-trigger.js +1 -1
  111. package/dist/panel.js +1 -1
  112. package/dist/postcss-tailwind3.js +1 -0
  113. package/dist/preferences.js +1 -2
  114. package/dist/provider.js +1 -1
  115. package/dist/server/fetch-ssr-data.js +1 -1
  116. package/dist/server/headers.js +1 -1
  117. package/dist/server/normalize-url.js +1 -1
  118. package/dist/styles.tw3.css +33 -51
  119. package/dist/transports/hosted.js +1 -0
  120. package/dist/transports/manifest.js +1 -0
  121. package/dist/transports/offline.js +1 -1
  122. package/dist/utils/deferred-module.js +2 -0
  123. package/dist/utils/merge-slot-props.js +1 -1
  124. package/dist/utils/theme-utils.js +1 -1
  125. package/dist/version.js +1 -1
  126. package/dist-types/aggregate-components.d.ts +2 -2
  127. package/dist-types/chunk-warming.d.ts +42 -8
  128. package/dist-types/component-hooks/use-headless-consent-ui.d.ts +5 -5
  129. package/dist-types/component-hooks/use-headless-iab-consent-ui.d.ts +2 -2
  130. package/dist-types/components/consent-gate/atoms.d.ts +11 -0
  131. package/dist-types/components/consent-gate/consent-gate.d.ts +2 -0
  132. package/dist-types/components/consent-gate/frame.d.ts +19 -0
  133. package/dist-types/components/consent-gate/index.d.ts +25 -0
  134. package/dist-types/components/{frame → consent-gate}/types.d.ts +7 -7
  135. package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +1 -1
  136. package/dist-types/components/consent-preferences-link/index.d.ts +1 -1
  137. package/dist-types/components/iab-panel/atoms/feature-item.d.ts +28 -0
  138. package/dist-types/components/iab-panel/atoms/purpose-item.d.ts +5 -2
  139. package/dist-types/components/iab-panel/atoms/stack-item.d.ts +7 -2
  140. package/dist-types/components/iab-panel/atoms/vendor-list.d.ts +1 -1
  141. package/dist-types/components/iab-panel/iab-panel.d.ts +3 -3
  142. package/dist-types/components/iab-panel/index.d.ts +29 -26
  143. package/dist-types/components/iab-panel/use-iab-translations.d.ts +4 -0
  144. package/dist-types/components/iab-prompt/iab-prompt.d.ts +3 -3
  145. package/dist-types/components/iab-prompt/index.d.ts +19 -19
  146. package/dist-types/components/panel/atoms/card.d.ts +5 -4
  147. package/dist-types/components/panel/atoms/overlay.d.ts +1 -1
  148. package/dist-types/components/panel/index.d.ts +8 -8
  149. package/dist-types/components/panel/panel.d.ts +3 -3
  150. package/dist-types/components/panel-link/index.d.ts +1 -1
  151. package/dist-types/components/panel-trigger/atoms/button.d.ts +1 -1
  152. package/dist-types/components/panel-trigger/atoms/icon.d.ts +1 -1
  153. package/dist-types/components/panel-trigger/atoms/root.d.ts +2 -2
  154. package/dist-types/components/panel-trigger/atoms/toolbar.d.ts +2 -2
  155. package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +25 -0
  156. package/dist-types/components/panel-trigger/index.d.ts +4 -4
  157. package/dist-types/components/panel-trigger/panel-trigger-toolbar.d.ts +1 -1
  158. package/dist-types/components/panel-trigger/panel-trigger.d.ts +9 -17
  159. package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
  160. package/dist-types/components/panel-trigger/types.d.ts +1 -1
  161. package/dist-types/components/preferences/atoms/accordion.d.ts +6 -4
  162. package/dist-types/components/preferences/atoms/button.d.ts +1 -1
  163. package/dist-types/components/preferences/atoms/footer.d.ts +1 -1
  164. package/dist-types/components/preferences/atoms/root.d.ts +1 -1
  165. package/dist-types/components/preferences/atoms/vendor-list.d.ts +23 -0
  166. package/dist-types/components/preferences/index.d.ts +14 -12
  167. package/dist-types/components/preferences/policy-actions.d.ts +2 -2
  168. package/dist-types/components/preferences/preferences.d.ts +1 -1
  169. package/dist-types/components/preferences/types.d.ts +1 -1
  170. package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
  171. package/dist-types/components/prompt/atoms/root.d.ts +4 -0
  172. package/dist-types/components/prompt/components.d.ts +9 -3
  173. package/dist-types/components/prompt/index.d.ts +12 -12
  174. package/dist-types/components/prompt/policy-actions.d.ts +2 -2
  175. package/dist-types/components/prompt/prompt.d.ts +5 -1
  176. package/dist-types/components/shared/dialog-sheets.d.ts +9 -0
  177. package/dist-types/components/shared/first-paint-sheets.d.ts +8 -0
  178. package/dist-types/components/shared/iab-dialog-sheets.d.ts +3 -0
  179. package/dist-types/components/shared/iab-first-paint-sheets.d.ts +3 -0
  180. package/dist-types/components/shared/libs/compose-refs.d.ts +20 -0
  181. package/dist-types/components/shared/policy-actions.d.ts +2 -2
  182. package/dist-types/components/shared/primitives/box.d.ts +1 -1
  183. package/dist-types/components/shared/primitives/button.d.ts +2 -2
  184. package/dist-types/components/shared/primitives/button.types.d.ts +1 -1
  185. package/dist-types/components/shared/streamed-surface.d.ts +23 -0
  186. package/dist-types/components/shared/surface-styles.d.ts +60 -0
  187. package/dist-types/components/shared/ui/accordion/accordion.d.ts +2 -2
  188. package/dist-types/components/shared/ui/accordion/index.d.ts +2 -2
  189. package/dist-types/components/shared/ui/animated-collapse/index.d.ts +2 -2
  190. package/dist-types/components/shared/ui/branding.d.ts +1 -1
  191. package/dist-types/components/shared/ui/button/button.d.ts +1 -1
  192. package/dist-types/components/shared/ui/button/index.d.ts +2 -2
  193. package/dist-types/components/shared/ui/collapsible/index.d.ts +1 -1
  194. package/dist-types/components/shared/ui/dialog/index.d.ts +1 -1
  195. package/dist-types/components/shared/ui/icon.d.ts +2 -1
  196. package/dist-types/components/shared/ui/logo.d.ts +0 -10
  197. package/dist-types/components/shared/ui/preference-item/index.d.ts +1 -1
  198. package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +13 -0
  199. package/dist-types/components/shared/ui/switch/index.d.ts +2 -2
  200. package/dist-types/components/shared/ui/switch/switch.d.ts +1 -1
  201. package/dist-types/components/shared/ui/tabs/index.d.ts +1 -1
  202. package/dist-types/consent-gate.d.ts +1 -0
  203. package/dist-types/consent-theme.d.ts +38 -0
  204. package/dist-types/context/consent-tracking-context.d.ts +10 -0
  205. package/dist-types/context/index.d.ts +3 -3
  206. package/dist-types/context/theme-context.d.ts +3 -3
  207. package/dist-types/context.d.ts +25 -1
  208. package/dist-types/devtools-launcher.d.ts +29 -0
  209. package/dist-types/devtools.d.ts +13 -2
  210. package/dist-types/draft-context.d.ts +31 -0
  211. package/dist-types/draft.d.ts +81 -9
  212. package/dist-types/gpp.d.ts +27 -0
  213. package/dist-types/headless.d.ts +6 -7
  214. package/dist-types/hooks/use-committed-ref.d.ts +24 -0
  215. package/dist-types/hooks/use-focus-trap.d.ts +3 -1
  216. package/dist-types/hooks/use-headless-iab-consent-ui.d.ts +1 -1
  217. package/dist-types/hooks/use-iab-manager.d.ts +5 -5
  218. package/dist-types/hooks/use-iab-policy-guard.d.ts +35 -0
  219. package/dist-types/hooks/use-late-entry.d.ts +14 -0
  220. package/dist-types/hooks/use-theme.d.ts +1 -1
  221. package/dist-types/hooks.d.ts +106 -11
  222. package/dist-types/iab-dialog-deferred.d.ts +36 -0
  223. package/dist-types/iab.d.ts +8 -7
  224. package/dist-types/index-parts/consent-banner.d.ts +7 -0
  225. package/dist-types/index-parts/consent-dialog-link.d.ts +7 -0
  226. package/dist-types/index-parts/consent-dialog-trigger.d.ts +7 -0
  227. package/dist-types/index-parts/consent-dialog.d.ts +7 -0
  228. package/dist-types/index-parts/consent-gate.d.ts +7 -0
  229. package/dist-types/index-parts/core.d.ts +7 -0
  230. package/dist-types/index-parts/draft.d.ts +7 -0
  231. package/dist-types/index-parts/frame.d.ts +7 -0
  232. package/dist-types/index-parts/hooks.d.ts +7 -0
  233. package/dist-types/index-parts/hosted.d.ts +7 -0
  234. package/dist-types/index-parts/module-hooks.d.ts +7 -0
  235. package/dist-types/index-parts/offline.d.ts +7 -0
  236. package/dist-types/index-parts/presets.d.ts +7 -0
  237. package/dist-types/index-parts/provider.d.ts +7 -0
  238. package/dist-types/index-parts/theme.d.ts +8 -0
  239. package/dist-types/index-parts/translations.d.ts +7 -0
  240. package/dist-types/index.d.ts +32 -28
  241. package/dist-types/kernel-selector.d.ts +68 -0
  242. package/dist-types/modes.d.ts +26 -0
  243. package/dist-types/module-hooks/iframe-blocker.d.ts +33 -1
  244. package/dist-types/module-hooks/network-blocker.d.ts +23 -0
  245. package/dist-types/module-hooks/network-hold.d.ts +47 -0
  246. package/dist-types/module-hooks.d.ts +4 -4
  247. package/dist-types/panel-link.d.ts +1 -1
  248. package/dist-types/panel-trigger.d.ts +1 -1
  249. package/dist-types/panel.d.ts +13 -1
  250. package/dist-types/postcss-tailwind3.d.ts +21 -0
  251. package/dist-types/preferences.d.ts +12 -1
  252. package/dist-types/primitives/accordion.d.ts +1 -1
  253. package/dist-types/primitives/button.d.ts +1 -1
  254. package/dist-types/primitives/collapsible.d.ts +1 -1
  255. package/dist-types/primitives/dialog.d.ts +1 -1
  256. package/dist-types/primitives/preference-item.d.ts +1 -1
  257. package/dist-types/primitives/switch.d.ts +1 -1
  258. package/dist-types/primitives/tabs.d.ts +1 -1
  259. package/dist-types/primitives.d.ts +7 -7
  260. package/dist-types/prompt.d.ts +1 -1
  261. package/dist-types/provider.d.ts +169 -28
  262. package/dist-types/server/fetch-ssr-data.d.ts +1 -1
  263. package/dist-types/server/headers.d.ts +14 -4
  264. package/dist-types/server/index.d.ts +5 -5
  265. package/dist-types/server/normalize-url.d.ts +14 -7
  266. package/dist-types/server/types.d.ts +12 -1
  267. package/dist-types/theme-provider.d.ts +2 -2
  268. package/dist-types/transports/hosted.d.ts +36 -0
  269. package/dist-types/transports/manifest.d.ts +48 -0
  270. package/dist-types/transports/offline.d.ts +7 -16
  271. package/dist-types/types/index.d.ts +3 -3
  272. package/dist-types/types/manager.d.ts +1 -1
  273. package/dist-types/types/theme/index.d.ts +1 -1
  274. package/dist-types/ui-config-context.d.ts +14 -2
  275. package/dist-types/utils/deferred-module.d.ts +13 -0
  276. package/dist-types/utils/index.d.ts +4 -4
  277. package/dist-types/utils/merge-slot-props.d.ts +17 -3
  278. package/dist-types/utils/merge-styles.d.ts +1 -1
  279. package/dist-types/utils/theme-utils.d.ts +18 -3
  280. package/dist-types/version.d.ts +1 -1
  281. package/docs/README.md +97 -70
  282. package/docs/assets/v3/bottom-bar.png +0 -0
  283. package/docs/assets/v3/brand-card.png +0 -0
  284. package/docs/assets/v3/brand-preferences.png +0 -0
  285. package/docs/assets/v3/choice-wall.png +0 -0
  286. package/docs/assets/v3/headless-bar-html.png +0 -0
  287. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  288. package/docs/assets/v3/headless-bar.png +0 -0
  289. package/docs/assets/v3/slim-bar.png +0 -0
  290. package/docs/concepts/choose-your-setup.md +141 -0
  291. package/docs/concepts/consent-categories.md +84 -0
  292. package/docs/concepts/consent-state.md +421 -0
  293. package/docs/concepts/data-fetching.md +284 -0
  294. package/docs/concepts/how-consent-works.md +123 -0
  295. package/docs/concepts/modes.md +281 -0
  296. package/docs/{frameworks/react/concepts/policy-presets.md → concepts/policies.md} +8 -60
  297. package/docs/customization/class-names.md +202 -0
  298. package/docs/customization/dark-mode.md +157 -0
  299. package/docs/customization/motion.md +128 -0
  300. package/docs/customization/overview.md +68 -33
  301. package/docs/customization/recipes.md +838 -47
  302. package/docs/customization/slots.md +217 -35
  303. package/docs/customization/stylesheets.md +248 -0
  304. package/docs/customization/tailwind.md +863 -0
  305. package/docs/customization/tokens.md +167 -36
  306. package/docs/customization/translations.md +87 -3
  307. package/docs/frameworks/react/callbacks.md +118 -0
  308. package/docs/frameworks/react/clear-on-revocation.md +106 -0
  309. package/docs/frameworks/react/components/consent-banner.md +48 -27
  310. package/docs/frameworks/react/components/consent-dialog-link.md +13 -11
  311. package/docs/frameworks/react/components/consent-dialog-trigger.md +86 -76
  312. package/docs/frameworks/react/components/consent-dialog.md +111 -58
  313. package/docs/frameworks/react/components/{frame.md → consent-gate.md} +70 -49
  314. package/docs/frameworks/react/components/consent-provider.md +143 -0
  315. package/docs/frameworks/react/components/consent-widget.md +69 -24
  316. package/docs/frameworks/react/components/dev-tools.md +76 -85
  317. package/docs/frameworks/react/components.md +113 -0
  318. package/docs/frameworks/react/compose.md +354 -0
  319. package/docs/frameworks/react/content-security-policy.md +149 -0
  320. package/docs/frameworks/react/customize.md +258 -0
  321. package/docs/frameworks/react/embeds.md +89 -0
  322. package/docs/frameworks/react/gpp.md +163 -0
  323. package/docs/frameworks/react/headless.md +4 -4
  324. package/docs/frameworks/react/hooks.md +70 -0
  325. package/docs/frameworks/react/iab.md +278 -0
  326. package/docs/frameworks/react/network-blocker.md +140 -0
  327. package/docs/frameworks/react/quickstart.md +171 -107
  328. package/docs/frameworks/react/rendering.md +285 -0
  329. package/docs/frameworks/react/scripts.md +114 -0
  330. package/docs/frameworks/react/translations.md +155 -0
  331. package/docs/frameworks/react/troubleshooting.md +189 -61
  332. package/docs/frameworks/react/upgrade-v3.md +652 -0
  333. package/docs/frameworks/react/vendor-consent.md +188 -0
  334. package/docs/guides/banner-experiments.md +688 -0
  335. package/docs/guides/troubleshooting.md +192 -54
  336. package/docs/guides/verify-consent.md +96 -49
  337. package/docs/integrations/adobe-analytics.md +177 -183
  338. package/docs/integrations/ahrefs-analytics.md +162 -178
  339. package/docs/integrations/amplitude.md +172 -180
  340. package/docs/integrations/building-integrations.md +137 -33
  341. package/docs/integrations/clearbit.md +164 -178
  342. package/docs/integrations/cloudflare-web-analytics.md +166 -180
  343. package/docs/integrations/cloudflare-zaraz.md +333 -0
  344. package/docs/integrations/crisp.md +174 -182
  345. package/docs/integrations/databuddy.md +167 -197
  346. package/docs/integrations/fathom-analytics.md +168 -180
  347. package/docs/integrations/front-chat.md +308 -0
  348. package/docs/integrations/google-maps.md +142 -108
  349. package/docs/integrations/google-tag-manager.md +258 -185
  350. package/docs/integrations/google-tag.md +226 -182
  351. package/docs/integrations/heap.md +173 -179
  352. package/docs/integrations/hightouch.md +171 -181
  353. package/docs/integrations/hotjar.md +169 -179
  354. package/docs/integrations/intercom.md +193 -177
  355. package/docs/integrations/klaviyo.md +473 -0
  356. package/docs/integrations/linkedin-insights.md +184 -174
  357. package/docs/integrations/logrocket.md +170 -180
  358. package/docs/integrations/matomo-analytics.md +198 -202
  359. package/docs/integrations/meta-pixel.md +198 -174
  360. package/docs/integrations/microsoft-clarity.md +173 -179
  361. package/docs/integrations/microsoft-uet.md +158 -178
  362. package/docs/integrations/mixpanel-analytics.md +165 -184
  363. package/docs/integrations/one-dollar-stats.md +292 -0
  364. package/docs/integrations/openai-pixel.md +214 -325
  365. package/docs/integrations/overview.md +153 -83
  366. package/docs/integrations/pinterest-tag.md +315 -0
  367. package/docs/integrations/pirsch.md +179 -183
  368. package/docs/integrations/plausible-analytics.md +182 -182
  369. package/docs/integrations/posthog.md +323 -264
  370. package/docs/integrations/promptwatch.md +164 -178
  371. package/docs/integrations/reddit-pixel.md +195 -181
  372. package/docs/integrations/rudderstack.md +211 -210
  373. package/docs/integrations/rybbit-analytics.md +181 -184
  374. package/docs/integrations/segment.md +192 -178
  375. package/docs/integrations/sentry.md +402 -0
  376. package/docs/integrations/snapchat-pixel.md +196 -180
  377. package/docs/integrations/tiktok-pixel.md +181 -174
  378. package/docs/integrations/umami-analytics.md +173 -182
  379. package/docs/integrations/vercel-analytics.md +176 -181
  380. package/docs/integrations/vercel-speed-insights.md +306 -0
  381. package/docs/integrations/x-pixel.md +186 -174
  382. package/docs/integrations/youtube.md +150 -111
  383. package/package.json +48 -17
  384. package/dist/component-hooks/use-manager.js +0 -2
  385. package/dist/components/frame/atoms.js +0 -1
  386. package/dist/components/frame/frame.js +0 -2
  387. package/dist/components/frame/index.js +0 -2
  388. package/dist/frame.js +0 -2
  389. package/dist/ui-save.js +0 -1
  390. package/dist-types/component-hooks/use-manager.d.ts +0 -40
  391. package/dist-types/components/frame/atoms.d.ts +0 -11
  392. package/dist-types/components/frame/frame.d.ts +0 -2
  393. package/dist-types/components/frame/index.d.ts +0 -24
  394. package/dist-types/frame.d.ts +0 -1
  395. package/dist-types/ui-save.d.ts +0 -5
  396. package/docs/assets/v3/brand-bar.png +0 -0
  397. package/docs/assets/v3/mobile-card.png +0 -0
  398. package/docs/assets/v3/preferences.png +0 -0
  399. package/docs/frameworks/react/components/consent-manager-provider.md +0 -71
  400. package/docs/frameworks/react/concepts/consent-categories.md +0 -33
  401. package/docs/frameworks/react/hooks/use-consent-manager/overview.md +0 -58
  402. package/docs/frameworks/react/iab/overview.md +0 -53
  403. package/docs/frameworks/react/script-loader.md +0 -63
  404. package/docs/frameworks/react/styling/overview.md +0 -217
  405. package/docs/guides/consent-state.md +0 -60
  406. package/docs/guides/data-fetching.md +0 -163
  407. package/docs/guides/deployment-modes.md +0 -63
  408. package/docs/integrations/clear-on-revocation.md +0 -167
  409. package/docs/upgrade-v3.md +0 -334
  410. package/readme.json +0 -48
  411. package/src/iab/styles.css +0 -11
  412. package/src/styles.css +0 -10
  413. /package/dist/components/{frame → consent-gate}/types.js +0 -0
@@ -0,0 +1,354 @@
1
+ ---
2
+ title: Compose your own banner
3
+ description: Build a React consent banner from the ConsentBanner parts in
4
+ c15t/react, with your own markup and buttons, while the policy still decides
5
+ which actions appear.
6
+ group: frameworks
7
+ ---
8
+
9
+ ## When to compose
10
+
11
+ Compose the banner from its parts when you need its elements in a different
12
+ order, an element it does not have, or your design system's button in place
13
+ of c15t's. The parts keep the stock
14
+ behavior. They read the same policy, record the same choices and render the
15
+ same class names, so theme tokens and slots still apply.
16
+
17
+ Try the lighter tools first:
18
+
19
+ | Change | Use |
20
+ | --------------------------------- | --------------------------------------------------------------------------------- |
21
+ | Colors, type, radius, spacing | [Theme tokens](../../customization/tokens.md) |
22
+ | Classes or attributes on one part | [Component parts](../../customization/slots.md) |
23
+ | Labels and languages | [Copy and translations](../../customization/translations.md) |
24
+ | Shape, position, button order | `ConsentBanner` props such as `variant`, `position`, `layout` and `primaryButton` |
25
+ | Different markup or order | Compound parts, on this page |
26
+ | Entirely custom UI and behavior | Headless hooks |
27
+
28
+ For a banner that shares nothing with the stock markup, use the
29
+ [headless hooks](./headless.md). For one changed class,
30
+ token or prop, see [customize](./customize.md).
31
+
32
+ ## Compose the banner
33
+
34
+ `CookieBanner` keeps the stock card, title and copy, and renders each action
35
+ the policy asks for as your design system's button. `BrandButton` stands in
36
+ for that button:
37
+
38
+ ```tsx title="src/brand-button.tsx"
39
+ import { forwardRef } from 'react';
40
+ import type { ButtonHTMLAttributes, ForwardedRef } from 'react';
41
+
42
+ interface BrandButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
43
+ tone?: 'solid' | 'outline';
44
+ }
45
+
46
+ const renderBrandButton = function renderBrandButton(
47
+ { className, tone = 'outline', type, ...props }: BrandButtonProps,
48
+ ref: ForwardedRef<HTMLButtonElement>
49
+ ) {
50
+ return (
51
+ <button
52
+ ref={ref}
53
+ {...props}
54
+ className={['brand-button', className].filter(Boolean).join(' ')}
55
+ data-tone={tone}
56
+ // Under `asChild`, c15t passes no type. Default to `button` so an
57
+ // action never submits a surrounding form.
58
+ type={type === 'submit' ? 'submit' : 'button'}
59
+ />
60
+ );
61
+ };
62
+
63
+ /**
64
+ * Your design system's button. To work under `asChild`, it forwards its ref
65
+ * and passes every other prop to the `button` element, so c15t's click
66
+ * handler, `data-action` and class names reach the DOM.
67
+ */
68
+ export const BrandButton = forwardRef(renderBrandButton);
69
+
70
+ BrandButton.displayName = 'BrandButton';
71
+ ```
72
+
73
+ ```tsx title="src/cookie-banner.tsx"
74
+ import { ConsentBanner, useTranslations } from 'c15t/react';
75
+
76
+ import { BrandButton } from './brand-button';
77
+
78
+ const actionParts = {
79
+ accept: ConsentBanner.AcceptButton,
80
+ customize: ConsentBanner.CustomizeButton,
81
+ dismiss: ConsentBanner.DismissButton,
82
+ reject: ConsentBanner.RejectButton,
83
+ } as const;
84
+
85
+ /**
86
+ * The stock card, title and copy, with each action the policy asks for
87
+ * rendered as your own button. `PolicyActions` decides which actions appear
88
+ * and in what order, so a notice still gets its acknowledgement.
89
+ */
90
+ export const CookieBanner = () => {
91
+ const { common } = useTranslations();
92
+ const labels = {
93
+ accept: common.acceptAll,
94
+ customize: common.customize,
95
+ dismiss: common.acknowledge,
96
+ reject: common.rejectAll,
97
+ };
98
+
99
+ return (
100
+ <ConsentBanner.Root>
101
+ <ConsentBanner.Card>
102
+ <ConsentBanner.Header>
103
+ <ConsentBanner.Title />
104
+ <ConsentBanner.Description />
105
+ </ConsentBanner.Header>
106
+ <ConsentBanner.PolicyActions
107
+ renderAction={(action, { key, isPrimary, ...props }) => {
108
+ if (action === 'save') {
109
+ return null;
110
+ }
111
+ const Action = actionParts[action];
112
+ return (
113
+ <Action key={key} {...props} asChild noStyle>
114
+ <BrandButton tone={isPrimary ? 'solid' : 'outline'}>
115
+ {labels[action]}
116
+ </BrandButton>
117
+ </Action>
118
+ );
119
+ }}
120
+ />
121
+ </ConsentBanner.Card>
122
+ </ConsentBanner.Root>
123
+ );
124
+ };
125
+ ```
126
+
127
+ The parts read the nearest `ConsentProvider`. In the `src/consent.tsx` file
128
+ from the [quickstart](./quickstart.md), import
129
+ `CookieBanner` from `./cookie-banner` and render it in place of
130
+ `ConsentBanner`, next to `ConsentDialog`:
131
+
132
+ ```tsx title="src/consent.tsx (partial)"
133
+ <ConsentProvider options={{ mode, scripts }}>
134
+ {children}
135
+ <CookieBanner />
136
+ <ConsentDialog />
137
+ <footer>
138
+ <ConsentDialogLink>Privacy settings</ConsentDialogLink>
139
+ </footer>
140
+ </ConsentProvider>;
141
+ ```
142
+
143
+ `ConsentBanner.Root` renders only while the banner is the active surface,
144
+ the same condition the stock `ConsentBanner` uses, so `CookieBanner` needs
145
+ no visibility logic. It renders nothing before a policy resolves and closes
146
+ once the visitor chooses.
147
+
148
+ `ConsentBanner.PolicyActions` renders the actions the policy asks for, in
149
+ the policy's order and groups, with any rights links, such as "Do not sell
150
+ or share my data", before them. For each action it calls `renderAction`
151
+ with the action name and the props c15t would give the stock button:
152
+ `key`, `consentAction`, `isPrimary`, and a `style` that stretches the
153
+ buttons when the layout fills the row. Return an element to replace that
154
+ button, or `null` to keep the stock one. The banner never renders `save`,
155
+ so the example skips it.
156
+
157
+ Each action part gets those props plus `asChild` and `noStyle`. `asChild`
158
+ renders `BrandButton` in place of c15t's `button`, and `noStyle` drops
159
+ c15t's button classes so they do not compete with yours. The part keeps its
160
+ behavior. Accept saves every category and Reject saves only necessary, and
161
+ both close the banner. Customize opens the preference dialog. Dismiss
162
+ records that the visitor saw a notice, without recording a choice.
163
+
164
+ With `asChild`, the part's default label does not render, because your
165
+ element keeps its own children. `useTranslations()` returns the labels the
166
+ stock buttons use, in the visitor's language.
167
+
168
+ Under a notice, the policy asks only for an acknowledgement, so
169
+ `PolicyActions` passes `dismiss` and `CookieBanner` renders one button. If
170
+ you place `ConsentBanner.AcceptButton` and `ConsentBanner.RejectButton`
171
+ yourself instead, they render under every policy, including one that owes
172
+ only a notice.
173
+
174
+ ## Banner parts
175
+
176
+ Every part is a property of `ConsentBanner`. All parts except `Root` and
177
+ `PolicyActions` forward their ref, and they accept the attributes of the
178
+ element they render plus `noStyle`.
179
+
180
+ | Part | Renders | Props |
181
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
182
+ | `Root` | The `div` that positions the banner, only while the banner shows. Renders the backdrop itself when blocking. | `variant`, `position`, `blocking`, `models` (default `['opt-in', 'opt-out']`), `uiSource` (default `'banner'`), `noStyle`, `disableAnimation` |
183
+ | `Card` | The visible `div`, labelled with the title. `role="region"`, or `role="dialog"` with `aria-modal="true"` and a focus trap when blocking. | `asChild` |
184
+ | `Header` | A `div` for the title and copy. | `asChild` |
185
+ | `Title` | An `h2` with the translated title, or the notice title under a notice. | children replace the text |
186
+ | `Description` | A `div` with the translated copy and the configured legal links. | `legalLinks`, `asChild` |
187
+ | `PolicyActions` | `Footer`, the rights links and the policy's action groups. | `renderAction`, children replace the rights links |
188
+ | `Footer` | A `div` for the actions. | `asChild` |
189
+ | `FooterSubGroup` | A `div` for one group of actions. `Actions` is an alias. | `asChild` |
190
+ | `AcceptButton` | A `button` that saves every category and closes the banner. | action button props |
191
+ | `RejectButton` | A `button` that saves only necessary and closes the banner. | action button props |
192
+ | `CustomizeButton` | A `button` that opens the preference dialog. | action button props |
193
+ | `DismissButton` | A `button` that acknowledges a notice. | action button props |
194
+ | `Rights` | A `div` with one `RightLink` per right the policy recommends, or nothing. | `rights`, `asChild` |
195
+ | `RightLink` | A `button` styled as underlined text that opens the preference dialog. | `right` (`'opt-out'` or `'preferences'`), `asChild` |
196
+ | `Overlay` | The backdrop of a blocking banner. `Root` already renders it, so do not add it. | none |
197
+
198
+ `Content` is an alias of `Card`.
199
+
200
+ The action buttons take `asChild`, `noStyle`, `consentAction`, `isPrimary`,
201
+ `variant` (`'primary'` or `'neutral'`), `mode` (`'filled'`, `'stroke'`,
202
+ `'lighter'` or `'ghost'`), `onClick` and any `button` attribute. Your
203
+ `onClick` runs before the action, and calling `event.preventDefault()` in
204
+ it skips the action. `consentAction` sets `data-action` and selects the
205
+ `theme.consentActions` entry. `PolicyActions` passes it for you, and
206
+ `DismissButton` sets it itself. A button you place yourself has no
207
+ `data-action` and no per-action theme until you pass `consentAction`.
208
+
209
+ `useConsentBannerSurface()` returns the `variant`, `position`,
210
+ `positionSource` and `blocking` that `Root` resolved, for your own elements
211
+ that depend on the banner's shape.
212
+
213
+ [ConsentBanner](./components/consent-banner.md) lists the
214
+ stock banner's props, variants and data attributes.
215
+
216
+ ## Render a part as your own element
217
+
218
+ `asChild` swaps the part's element for the one element you pass as its
219
+ child. `Card`, `Header`, `Description`, `Footer`, `FooterSubGroup`,
220
+ `Rights`, `RightLink` and the action buttons support it. `Root` and
221
+ `Overlay` ignore it, and `Title` always renders an `h2`, so a child you pass
222
+ to `Title` ends up inside that `h2`. `Description` with `asChild` drops the
223
+ inline legal links.
224
+
225
+ The part merges its props onto your element:
226
+
227
+ * The part's props apply first, and props you set on the child win.
228
+ * `className` keeps both, the part's classes first.
229
+ * `style` merges, and your values win per property.
230
+ * Event handlers both run, yours first. On an action button, calling
231
+ `event.preventDefault()` in yours skips c15t's action.
232
+ * The part's ref and your child's ref both receive the DOM node.
233
+ * Your child keeps its own children. The part's default content, such as a
234
+ button label, does not render.
235
+
236
+ Your component has to pass its ref and every prop it does not use to its
237
+ DOM element. Otherwise c15t's click handler, `data-action` and focus
238
+ handling never reach the page. The `BrandButton` in the example does both.
239
+ Pass exactly one element. Text, a fragment or several children render
240
+ nothing.
241
+
242
+ Action buttons pass no `type` under `asChild`, so give your button a
243
+ default of `type="button"`. Without it, the button submits a surrounding
244
+ form.
245
+
246
+ ## Compose the preference dialog
247
+
248
+ `ConsentDialog` has parts too. Compose it when the dialog needs a different
249
+ header or footer, and keep `ConsentWidget` inside `Content`. The widget
250
+ owns the category switches, the draft and the policy's Save, Accept and
251
+ Reject buttons.
252
+
253
+ | Part | Renders | Props |
254
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
255
+ | `Root` | The dialog in a portal on `document.body`, with its open state, backdrop, focus trap, scroll lock and Escape to close. | `open`, `models` (default `['opt-in', 'opt-out', 'none']`), `overlay` (a node, or `false` for none), `noStyle`, `disableAnimation`, `scrollLock`, `trapFocus`, `uiSource` (default `'dialog'`) |
256
+ | `Card` | The panel `div`. | `className`, `style`, `noStyle` |
257
+ | `Header` | A `div` for the title and copy. | `asChild` |
258
+ | `HeaderTitle` | An `h2` with `id="consent-dialog-title"`. | children replace the text |
259
+ | `HeaderDescription` | A `div` with `id="consent-dialog-description"` and the legal links. | `legalLinks`, `asChild` |
260
+ | `Content` | A `div` for `ConsentWidget`. | `asChild` |
261
+ | `Footer` | A `div` with the branding tag, unless you pass children or `hideBranding`. | `hideBranding`, `asChild` |
262
+ | `ConsentCustomizationCard` | The stock card with all of the above. | `legalLinks`, `hideBranding`, `noStyle` |
263
+ | `Overlay` | The backdrop. `Root` already renders it. | none |
264
+
265
+ ```tsx
266
+ <ConsentDialog.Root>
267
+ <ConsentDialog.Card>
268
+ <ConsentDialog.Header>
269
+ <ConsentDialog.HeaderTitle>Your privacy choices</ConsentDialog.HeaderTitle>
270
+ <ConsentDialog.HeaderDescription />
271
+ </ConsentDialog.Header>
272
+ <ConsentDialog.Content>
273
+ <ConsentWidget />
274
+ </ConsentDialog.Content>
275
+ <ConsentDialog.Footer hideBranding />
276
+ </ConsentDialog.Card>
277
+ </ConsentDialog.Root>
278
+ ```
279
+
280
+ Render the composed dialog in place of `ConsentDialog`, next to your
281
+ banner. The stock `ConsentDialog` downloads its code when the dialog first
282
+ opens. The parts load that same code when they first render, and a
283
+ composed `ConsentDialog.Root` renders on every page, so the code downloads
284
+ with the page. `c15t/react/components/consent-dialog` exports the same
285
+ parts without the deferral.
286
+
287
+ `ConsentWidget` has parts as well, such as `ConsentWidget.Root`,
288
+ `ConsentWidget.Accordion`, `ConsentWidget.AccordionItems` and
289
+ `ConsentWidget.PolicyActions`, for a preference list with your own layout.
290
+
291
+ The parts come from `c15t/react`, like `ConsentDialog` and `ConsentWidget`.
292
+ [ConsentDialog](./components/consent-dialog.md) and
293
+ [ConsentWidget](./components/consent-widget.md) list every
294
+ part and its slots.
295
+
296
+ ## Keep the banner accessible
297
+
298
+ The stock parts carry the roles, labels and focus handling. A composed
299
+ banner keeps them as long as you keep the parts that own them:
300
+
301
+ * `Card` owns the banner's role, label and focus trap. With `asChild`, your
302
+ element receives them, so do not set `role` or `aria-modal` on it.
303
+ * `Card` takes its `aria-label` from the translated title, not from text you
304
+ pass to `Title`. If you change the title text, pass the same text as
305
+ `aria-label` on `Card`.
306
+ * To attach your own ref to `Card`, pass a ref object from `useRef`. A
307
+ callback ref turns off the focus trap on a blocking banner.
308
+ * Render each action as a real `button`. Its text is the accessible name,
309
+ so keep the label inside your button.
310
+ * Keep a way to reopen preferences after the banner closes, such as the
311
+ `ConsentDialogLink` in your footer.
312
+ * The dialog's `Root` names the panel with the ids on `HeaderTitle` and
313
+ `HeaderDescription`. Keep both parts, or put `id="consent-dialog-title"`
314
+ and `id="consent-dialog-description"` on your own heading and copy.
315
+
316
+ ## Keep theme tokens and slots working
317
+
318
+ The parts render the stock class names, and the banner's `Root` renders
319
+ c15t's rules, so c15t's styles and `--c15t-*` tokens style a composed
320
+ banner the way they style the stock one.
321
+
322
+ Slots in the provider's `options.components` reach each part by key:
323
+ `banner.root`, `banner.card`, `banner.header`, `banner.title`,
324
+ `description.banner`, `banner.footer` and `banner.actions`,
325
+ `banner.actionGroup`, `banner.rights` and `banner.rightLink`. A class you
326
+ pass to a part joins its stock and slot classes. The stock `ConsentBanner`
327
+ also renders the `banner.cardShell` wrapper and the "Secured by" tag, and a
328
+ composed banner renders neither.
329
+
330
+ Action buttons read the `button.primary` or `button.secondary` slot and the
331
+ `theme.consentActions` entry for their `consentAction`. `noStyle` on a
332
+ button drops c15t's button classes and keeps slot classes. `noStyle` on
333
+ `Root` removes the built-in styling from every part inside it.
334
+
335
+ [Customize](./customize.md) shows where to set tokens,
336
+ slots and `consentActions` in a React app.
337
+
338
+ ## Check the result
339
+
340
+ 1. Clear site data and reload. The composed banner appears with your
341
+ buttons. In DevTools Elements, each action is your element with a
342
+ `data-action` attribute. In DevTools Network, no optional vendor request
343
+ has fired.
344
+ 2. Tab through the banner. Every action is reachable in the policy's order
345
+ and shows a focus ring. Press Enter on Customize, and the preference
346
+ dialog opens.
347
+ 3. Click Reject all. The banner closes. Reload, and it stays closed with
348
+ the vendors still blocked.
349
+ 4. Reopen preferences from your footer link. The optional categories are
350
+ off. Allow one, save, and only that category's vendors load.
351
+ 5. If your policies include a notice region, test it too. The banner shows
352
+ your acknowledgement button and no Accept or Reject.
353
+
354
+ [Verify consent](../../guides/verify-consent.md) has the full checklist.
@@ -0,0 +1,149 @@
1
+ ---
2
+ title: Content Security Policy
3
+ description: Run c15t in a React app under a Content Security Policy, allow the
4
+ consent backend and vendor hosts, and pass a nonce to ConsentProvider and
5
+ ConsentTheme.
6
+ group: frameworks
7
+ ---
8
+
9
+ ## What c15t adds to the page
10
+
11
+ A React app with c15t adds these to the page, and your policy must allow them:
12
+
13
+ | What | Directive |
14
+ | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
15
+ | The `<style>` elements the banner, dialog and other stock components render with c15t's rules | `style-src` with a nonce |
16
+ | `c15t/react/styles.css`, only if you import it with `styles: false` | `style-src 'self'` |
17
+ | The `<style id="c15t-theme">` element, if you render `ConsentTheme` | `style-src` with a nonce or its hash |
18
+ | `<script>` elements the script loader creates for `scripts` entries, both `src` and inline | `script-src` with each vendor's host, or a nonce |
19
+ | The inline `<script>` that `consentManifest()` adds to `index.html` to send `/init` early | `script-src` with a nonce or its hash |
20
+ | With server rendering, the inline `<script>` before the banner's buttons that holds a tap made before hydration | `script-src` with a nonce or its hash |
21
+ | Browser requests to your backend's `/init` and `/subjects` | `connect-src` with the backend origin |
22
+ | Iframes inside `ConsentGate`, and the frames, images and requests your vendors load | `frame-src`, `img-src`, `connect-src` for each vendor |
23
+
24
+ In a client-rendered app, c15t components set their inline styles through
25
+ React. A policy does not restrict styles set that way, so they need no
26
+ directive.
27
+
28
+ ## Allow the consent backend
29
+
30
+ With `hosted()`, the browser calls `GET {url}/init` on every page load
31
+ and `POST {url}/subjects` when the visitor accepts, rejects or saves. With
32
+ `manifest()`, it calls `POST {url}/subjects`, and `GET {url}/init` only when
33
+ the policy needs a location the browser does not know. Add the
34
+ backend's origin to `connect-src`:
35
+
36
+ ```txt title="Content-Security-Policy (partial)"
37
+ connect-src 'self' https://<your-backend-host>;
38
+ ```
39
+
40
+ Use the origin of the backend URL from your Inth project or self-hosted
41
+ backend. When the URL is a same-origin path such as `/api/c15t` behind your
42
+ own proxy, `'self'` covers it.
43
+
44
+ Under an IAB TCF policy the browser also loads the Global Vendor List from the
45
+ URL the policy provides. Allow that host in `connect-src` if you use the
46
+ [IAB TCF add-on](./iab.md).
47
+
48
+ ## Allow vendor scripts
49
+
50
+ The script loader adds a `<script>` element for each `scripts` entry once its
51
+ category is allowed. List each vendor's script host in `script-src`, and the
52
+ hosts its script calls in `connect-src` and `img-src`. The vendor's own
53
+ documentation lists them. Scripts that a vendor script adds itself, such as a
54
+ tag manager's tags, need their own hosts too, or `'strict-dynamic'` with a
55
+ nonce.
56
+
57
+ A `scripts` entry with inline `textContent` instead of `src` needs a nonce or
58
+ its hash in `script-src`.
59
+
60
+ ## Use a nonce
61
+
62
+ A nonce protects a page only when it changes on every response. A static host
63
+ serves the same file to everyone, so use host allowlists there. Use a nonce
64
+ when a server renders or rewrites your `index.html` per request.
65
+
66
+ Pass the nonce as `options.nonce` on `ConsentProvider`. The script loader
67
+ stamps it on every `<script>` it creates. A `nonce` on a single `scripts`
68
+ entry takes precedence for that element. The stock components put it on the
69
+ `<style>` elements that carry c15t's rules.
70
+
71
+ With Vite, set `html.cspNonce` to a placeholder in `vite.config.ts`, and have
72
+ your server replace it with a new nonce on every response. Vite then adds
73
+ `<meta property="csp-nonce" nonce="...">` to the page, and the browser keeps the
74
+ value in the tag's `nonce` property. Vite also stamps the nonce on the early
75
+ `/init` script. Read it where you create the provider, in the
76
+ quickstart's `src/consent.tsx`:
77
+
78
+ ```tsx title="src/consent.tsx (partial)"
79
+ const nonce =
80
+ document.querySelector<HTMLMetaElement>('meta[property="csp-nonce"]')
81
+ ?.nonce || undefined;
82
+
83
+ <ConsentProvider options={{ mode, scripts, nonce }}>
84
+ ```
85
+
86
+ If you render `ConsentTheme`, pass it the same value:
87
+ `<ConsentTheme theme={theme} nonce={nonce} />`.
88
+
89
+ The provider reads `options.nonce` once, when it mounts. A server-rendered
90
+ React app, such as one built with React Router framework mode, reads the nonce
91
+ from its own request and passes it the same way.
92
+
93
+ On a static host, allow the early `/init` script by the hash in the browser's
94
+ `Refused to execute inline script` error. If the policy blocks it, the app
95
+ sends `/init` itself.
96
+
97
+ ## Allow c15t's style elements
98
+
99
+ The banner, dialog and other stock components render c15t's rules as
100
+ `<style>` elements. A `style-src` without `'unsafe-inline'` must admit them.
101
+ Either:
102
+
103
+ * Set `options.nonce` on `ConsentProvider`, as in [use a nonce](#use-a-nonce).
104
+ The elements then render next to each component with the nonce. React 19
105
+ would otherwise move them into `<head>` and drop the nonce.
106
+ * Or set `styles: false` in the provider options and import
107
+ `c15t/react/styles.css` from your bundle. `style-src 'self'` admits it.
108
+
109
+ ## Allow the theme style element
110
+
111
+ `ConsentTheme` renders your theme tokens into a `<style id="c15t-theme">`
112
+ element. Without a nonce, a `style-src` that lacks `'unsafe-inline'` blocks it,
113
+ and the banner falls back to the default theme. The element's content depends
114
+ only on the theme, so a hash works:
115
+
116
+ 1. Load the page with the policy enforced.
117
+ 2. Copy the `sha256-...` value from the `Refused to apply inline style`
118
+ console error.
119
+ 3. Add it to `style-src` and redeploy.
120
+
121
+ Recompute the hash when you change the theme. To avoid the hash, set the
122
+ tokens in your own stylesheet instead, as
123
+ [customize](./customize.md) shows.
124
+
125
+ ## Allow embeds and the dev server
126
+
127
+ Add the host of every iframe you gate to `frame-src`. A YouTube player inside
128
+ `ConsentGate` needs `https://www.youtube-nocookie.com`, for example.
129
+
130
+ Vite's dev server injects CSS as `<style>` elements, and the DevTools panel
131
+ adds a `<style>` element without a nonce. Test the policy against a
132
+ production build.
133
+
134
+ ## Verify
135
+
136
+ Build the app, serve it with the policy enforced, not in report-only mode, and
137
+ open DevTools. Test under a policy that asks for a choice, such as an EU
138
+ opt-in policy.
139
+
140
+ 1. The banner renders with its theme colors, and the console shows no
141
+ `Refused to` error that mentions a c15t element, your backend or a vendor.
142
+ 2. Before a choice, the Network tab shows no vendor requests.
143
+ 3. Click **Accept All**. The vendor scripts load, and their `<script>` elements have ids
144
+ starting `c15t-`. With a nonce, read each element's `nonce` property in the
145
+ console. Browsers hide the attribute from `getAttribute`.
146
+ 4. The save to `/subjects` succeeds. A `connect-src` violation here means the
147
+ backend origin is missing.
148
+ 5. Reload. The banner stays closed, and the vendors load without a console
149
+ error.