@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,863 @@
1
+ ---
2
+ title: Tailwind CSS
3
+ description: Use c15t's styles with Tailwind CSS 4 or 3 in every framework, put
4
+ utilities on c15t component parts, and use Tailwind's dark variant with c15t.
5
+ group: customization
6
+ ---
7
+
8
+ ## How c15t's styles meet Tailwind
9
+
10
+ c15t's component rules live in the CSS cascade layer `components`. Each c15t
11
+ stylesheet starts with Tailwind CSS 4's layer order,
12
+ `@layer properties, theme, base, components, utilities;`, and cascade layers
13
+ rank by the order they are first named. On Tailwind 4, c15t's rules stay above
14
+ Tailwind's preflight in `base` and below your utilities in `utilities`,
15
+ whichever stylesheet loads first. A plain utility such as `p-2` on a c15t part
16
+ wins without `!important`.
17
+
18
+ Tailwind CSS 3 has no cascade layers. It treats `@layer components` as its own
19
+ directive and fails the build on a stylesheet that uses it without a matching
20
+ `@tailwind components`. c15t's Tailwind 3 PostCSS plugin removes the layer
21
+ wrappers from c15t's stylesheets before Tailwind 3 runs. c15t's rules then
22
+ win by specificity, as they did in c15t v2, so a utility on a c15t part needs
23
+ Tailwind's important modifier, such as `!p-2`. The plugin cannot reach the
24
+ `<style>` elements c15t renders itself, so on Tailwind 3 you turn those off
25
+ with `styles: false` and import the stylesheet instead. The Astro integration
26
+ does this for you when it finds Tailwind 3.
27
+
28
+ The setups below come from fixtures that CI builds for each framework and
29
+ checks in Chromium. The Next.js snippets come from the Next.js 16 Turbopack
30
+ fixture. The Next.js 15 and webpack fixtures use the same files. The check
31
+ confirms that c15t's banner and dialog keep their styles under Tailwind's
32
+ preflight, that a padding utility on the banner root
33
+ beats c15t's own padding, and that the `dark:` variant applies. The fixtures run
34
+ without a backend, so they use `offline()` mode or a local `backendURL`. Keep the
35
+ `mode` or `backendURL` from your quickstart.
36
+
37
+ ## Set up Tailwind CSS 4
38
+
39
+ Install Tailwind's plugin for your build tool and add it to the build. c15t
40
+ loads its own styles in every framework, so your CSS entry holds only
41
+ Tailwind. Do not import c15t's stylesheet next to Tailwind 4: the stock
42
+ components already render the same rules, and the import would hold back the
43
+ first paint.
44
+
45
+ **Next.js**
46
+
47
+ Next.js runs Tailwind 4 through `@tailwindcss/postcss`:
48
+
49
+ ```js title="postcss.config.mjs"
50
+ export default { plugins: { '@tailwindcss/postcss': {} } };
51
+ ```
52
+
53
+ Import Tailwind in the global stylesheet that `app/layout.tsx` or
54
+ `pages/_app.tsx` loads:
55
+
56
+ ```css title="app/globals.css"
57
+ @import 'tailwindcss';
58
+
59
+ @custom-variant dark (&:where(.dark, .dark *));
60
+ ```
61
+
62
+ **TanStack Start**
63
+
64
+ Add `@tailwindcss/vite` before the TanStack Start plugin:
65
+
66
+ ```ts title="vite.config.ts"
67
+ import tailwindcss from '@tailwindcss/vite';
68
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite';
69
+ import react from '@vitejs/plugin-react';
70
+ import { defineConfig } from 'vite';
71
+
72
+ export default defineConfig({
73
+ plugins: [
74
+ tailwindcss(),
75
+ tanstackStart({ prerender: { enabled: true } }),
76
+ react(),
77
+ ],
78
+ });
79
+ ```
80
+
81
+ Import Tailwind from the stylesheet your root route links:
82
+
83
+ ```css title="src/styles.css"
84
+ @import 'tailwindcss';
85
+
86
+ @custom-variant dark (&:where(.dark, .dark *));
87
+ ```
88
+
89
+ **React**
90
+
91
+ ```ts title="vite.config.ts"
92
+ import tailwindcss from '@tailwindcss/vite';
93
+ import react from '@vitejs/plugin-react';
94
+ import { defineConfig } from 'vite';
95
+
96
+ export default defineConfig({ plugins: [react(), tailwindcss()] });
97
+ ```
98
+
99
+ Import this stylesheet from your entry module:
100
+
101
+ ```css title="src/app.css"
102
+ @import 'tailwindcss';
103
+
104
+ @custom-variant dark (&:where(.dark, .dark *));
105
+ ```
106
+
107
+ **Nuxt**
108
+
109
+ Add `@tailwindcss/vite` under `vite.plugins` and list your CSS entry in
110
+ `css`. The Vue components load c15t's styles themselves:
111
+
112
+ ```ts title="nuxt.config.ts"
113
+ import tailwindcss from '@tailwindcss/vite';
114
+ import { hosted } from 'c15t/vue';
115
+
116
+ export default defineNuxtConfig({
117
+ c15t: { backendURL: '/api/c15t', mode: hosted() },
118
+ compatibilityDate: '2026-07-04',
119
+ css: ['~/assets/css/main.css'],
120
+ modules: ['c15t/vue'],
121
+ ssr: false,
122
+ vite: { plugins: [tailwindcss()] },
123
+ });
124
+ ```
125
+
126
+ Your CSS entry imports Tailwind and declares the dark variant:
127
+
128
+ ```css title="app/assets/css/main.css"
129
+ @import 'tailwindcss';
130
+
131
+ @custom-variant dark (&:where(.dark, .dark *));
132
+ ```
133
+
134
+ **Vue**
135
+
136
+ The Vue components load their own stylesheets, so the CSS entry holds only
137
+ Tailwind:
138
+
139
+ ```ts title="vite.config.ts"
140
+ import tailwindcss from '@tailwindcss/vite';
141
+ import vue from '@vitejs/plugin-vue';
142
+ import { consentManifest } from 'c15t/vue/vite';
143
+ import { defineConfig } from 'vite';
144
+
145
+ export default defineConfig({
146
+ plugins: [vue(), consentManifest({ backendURL: '/api/c15t' }), tailwindcss()],
147
+ });
148
+ ```
149
+
150
+ Import this stylesheet from `src/main.ts`:
151
+
152
+ ```css title="src/style.css"
153
+ @import 'tailwindcss';
154
+
155
+ @custom-variant dark (&:where(.dark, .dark *));
156
+ ```
157
+
158
+ **Astro**
159
+
160
+ c15t inlines the banner's rules into each page and links the dialog's
161
+ when it opens, so the CSS entry holds only Tailwind. Add
162
+ `@tailwindcss/vite` under `vite.plugins`:
163
+
164
+ ```js title="astro.config.mjs"
165
+ import svelte from '@astrojs/svelte';
166
+ import tailwindcss from '@tailwindcss/vite';
167
+ import { defineConfig } from 'astro/config';
168
+ import c15t, { offline } from 'c15t/astro';
169
+
170
+ export default defineConfig({
171
+ integrations: [
172
+ svelte(),
173
+ c15t({
174
+ mode: offline({
175
+ policyRules: [
176
+ {
177
+ id: 'tailwind-matrix',
178
+ match: { isDefault: true },
179
+ model: 'opt-in',
180
+ prompt: 'choice',
181
+ },
182
+ ],
183
+ }),
184
+ }),
185
+ ],
186
+ vite: { plugins: [tailwindcss()] },
187
+ });
188
+ ```
189
+
190
+ Import this stylesheet from your layout:
191
+
192
+ ```css title="src/styles/global.css"
193
+ @import 'tailwindcss';
194
+
195
+ @custom-variant dark (&:where(.dark, .dark *));
196
+ ```
197
+
198
+ **Svelte**
199
+
200
+ ```ts title="vite.config.ts"
201
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
202
+ import tailwindcss from '@tailwindcss/vite';
203
+ import { defineConfig } from 'vite';
204
+
205
+ export default defineConfig({ plugins: [svelte(), tailwindcss()] });
206
+ ```
207
+
208
+ Import this stylesheet from `src/main.ts`:
209
+
210
+ ```css title="src/app.css"
211
+ @import 'tailwindcss';
212
+
213
+ @custom-variant dark (&:where(.dark, .dark *));
214
+ ```
215
+
216
+ **SvelteKit**
217
+
218
+ ```ts title="vite.config.ts"
219
+ import { sveltekit } from '@sveltejs/kit/vite';
220
+ import tailwindcss from '@tailwindcss/vite';
221
+ import { defineConfig } from 'vite';
222
+
223
+ export default defineConfig({ plugins: [tailwindcss(), sveltekit()] });
224
+ ```
225
+
226
+ Import this stylesheet from your root `+layout.svelte`:
227
+
228
+ ```css title="src/app.css"
229
+ @import 'tailwindcss';
230
+
231
+ @custom-variant dark (&:where(.dark, .dark *));
232
+ ```
233
+
234
+ **HTML**
235
+
236
+ The script tag renders its UI in a shadow root with its own copy of c15t's
237
+ stylesheet. Build your Tailwind CSS as usual and link it from the page:
238
+
239
+ ```css title="style.css"
240
+ @import 'tailwindcss';
241
+
242
+ @custom-variant dark (&:where(.dark, .dark *));
243
+ ```
244
+
245
+ To put utilities on c15t's parts, link the same build into the shadow root
246
+ with `ui.stylesheetURLs`, as in
247
+ [put utilities on c15t parts](#put-utilities-on-c15t-parts).
248
+
249
+ **JavaScript**
250
+
251
+ `init()` from `@c15t/browser` renders into a shadow root, the same way as
252
+ the script tag. Build Tailwind as usual for your page. To put utilities on
253
+ c15t's parts, pass the URL of your built stylesheet in
254
+ `ui.stylesheetURLs`, as in
255
+ [put utilities on c15t parts](#put-utilities-on-c15t-parts).
256
+
257
+ ## Set up Tailwind CSS 3
258
+
259
+ Tailwind 3's preflight is unlayered, so it beats the layered rules c15t
260
+ renders itself and strips the banner's padding and borders. On Tailwind 3,
261
+ turn those rules off with `styles: false` and import c15t's `styles.css`
262
+ through a PostCSS plugin. The Astro integration needs only the plugin: it
263
+ detects Tailwind 3 and links `c15t/astro/styles.css` itself. Every c15t
264
+ package that ships a stylesheet exports the plugin as
265
+ `<package>/postcss-tailwind3`, so use the one from the package you installed:
266
+
267
+ | You installed | Plugin name |
268
+ | --------------------------------------------------------- | --------------------------------- |
269
+ | `c15t` (React, Next.js, TanStack Start, Vue, Nuxt, Astro) | `c15t/postcss-tailwind3` |
270
+ | `@c15t/svelte` (Svelte, SvelteKit) | `@c15t/svelte/postcss-tailwind3` |
271
+ | `@c15t/browser` (script tag in the light DOM) | `@c15t/browser/postcss-tailwind3` |
272
+
273
+ They are the same plugin. A config that already lists
274
+ `@c15t/ui/postcss-tailwind3` keeps working.
275
+
276
+ Make four changes:
277
+
278
+ 1. Set `styles: false` where you configure c15t: `options` in Next.js
279
+ `c15t.config.ts`, `options` on `ConsentRoot` in TanStack Start, `options`
280
+ on `ConsentProvider` in React, and `styles={false}` on `ConsentProvider` in
281
+ Svelte or `ConsentRoot` in SvelteKit.
282
+ Vue, Nuxt and Astro need no change.
283
+ 2. Add the plugin to your PostCSS plugins, before `tailwindcss`. Write the plugins as an object, as the examples below do.
284
+ PostCSS runs them in the order of the keys. Next.js also accepts an array
285
+ of plugin names, but Vite's PostCSS loader rejects that form.
286
+ 3. Import c15t's stylesheet above the `@tailwind` directives, whatever your
287
+ build tool. Vue, Nuxt and Astro skip this step. Vite drops an `@import`
288
+ that follows another rule, with the warning
289
+ `@import must precede all other statements`, and the banner renders
290
+ unstyled. Next.js 16 with Turbopack fails the build.
291
+ 4. Set `darkMode: 'class'` so Tailwind's `dark:` variant follows the same
292
+ `dark` class c15t reads.
293
+
294
+ The plugin also processes the stylesheets the Vue and Nuxt components import,
295
+ and the one the Astro integration adds on a Tailwind 3 site. Without it,
296
+ Tailwind 3 stops
297
+ the build with "`@layer components` is used but no matching
298
+ `@tailwind components` directive is present", or purges c15t's rules, because
299
+ c15t's class names never appear in your source.
300
+
301
+ Tailwind 3 has no cascade layers, so c15t's selectors outrank a single utility
302
+ class. Add the important modifier to utilities you pass to c15t parts:
303
+ `!bg-red-500`, `hover:!bg-red-500`. A bare `bg-red-500` has no effect. Theme
304
+ tokens work the same on Tailwind 3 and 4.
305
+
306
+ In React and Next.js apps, `c15t setup` adds the plugin and the stylesheet
307
+ import when it finds Tailwind 3, but does not set `styles: false`. Add that
308
+ yourself. It replaces an existing
309
+ `styles.tw3.css` import from an earlier setup with `styles.css`. When it
310
+ cannot edit your PostCSS config, it prints the step to do by hand. See
311
+ [setup](https://v3.c15t.com/docs/cli/commands/setup#set-up-styles-and-tailwind-css).
312
+
313
+ Create React App ignores PostCSS config files, so Tailwind 3 cannot run the
314
+ plugin and the build fails on c15t's stylesheet. `c15t setup` warns
315
+ about this. Add the plugin before `tailwindcss` through CRACO, eject, or move
316
+ the app to Vite.
317
+
318
+ **Next.js**
319
+
320
+ Next.js loads `postcss.config.mjs` itself:
321
+
322
+ ```js title="postcss.config.mjs"
323
+ export default {
324
+ plugins: { 'c15t/postcss-tailwind3': {}, tailwindcss: {}, autoprefixer: {} },
325
+ };
326
+ ```
327
+
328
+ Scan `app/` and turn on the class-based dark variant:
329
+
330
+ ```ts title="tailwind.config.ts"
331
+ import type { Config } from 'tailwindcss';
332
+
333
+ export default {
334
+ content: ['./app/**/*.{ts,tsx}'],
335
+ darkMode: 'class',
336
+ } satisfies Config;
337
+ ```
338
+
339
+ Import `c15t/next/styles.css` above the directives. Turbopack fails the
340
+ build when the import sits below them. The same order works with
341
+ webpack. Set `styles: false` in `ConsentRoot`'s `options` as well:
342
+
343
+ ```css title="app/globals.css"
344
+ /* Turbopack rejects an @import below other rules, so it goes first. */
345
+ @import 'c15t/next/styles.css';
346
+
347
+ @tailwind base;
348
+ @tailwind components;
349
+ @tailwind utilities;
350
+ ```
351
+
352
+ **TanStack Start**
353
+
354
+ ```js title="postcss.config.mjs"
355
+ export default {
356
+ plugins: { 'c15t/postcss-tailwind3': {}, tailwindcss: {}, autoprefixer: {} },
357
+ };
358
+ ```
359
+
360
+ Scan your source and turn on the class-based dark variant:
361
+
362
+ ```ts title="tailwind.config.ts"
363
+ import type { Config } from 'tailwindcss';
364
+
365
+ export default {
366
+ content: ['./src/**/*.{ts,tsx}'],
367
+ darkMode: 'class',
368
+ } satisfies Config;
369
+ ```
370
+
371
+ Import `c15t/tanstack-start/styles.css` above the directives, in the
372
+ stylesheet your root route links, and set `styles: false` in
373
+ `ConsentRoot`'s `options`:
374
+
375
+ ```css title="src/styles.css"
376
+ /* Vite ignores an @import below other rules, so it goes first. */
377
+ @import 'c15t/tanstack-start/styles.css';
378
+
379
+ @tailwind base;
380
+ @tailwind components;
381
+ @tailwind utilities;
382
+ ```
383
+
384
+ **React**
385
+
386
+ ```js title="postcss.config.mjs"
387
+ export default {
388
+ plugins: { 'c15t/postcss-tailwind3': {}, tailwindcss: {}, autoprefixer: {} },
389
+ };
390
+ ```
391
+
392
+ Scan your source and turn on the class-based dark variant:
393
+
394
+ ```ts title="tailwind.config.ts"
395
+ import type { Config } from 'tailwindcss';
396
+
397
+ export default {
398
+ content: ['./index.html', './src/**/*.{ts,tsx}'],
399
+ darkMode: 'class',
400
+ } satisfies Config;
401
+ ```
402
+
403
+ Import `c15t/react/styles.css` above the directives, import this
404
+ stylesheet from your entry module, and set `styles: false` in the
405
+ `ConsentProvider` options:
406
+
407
+ ```css title="src/app.css"
408
+ /* Vite ignores an @import below other rules, so it goes first. */
409
+ @import 'c15t/react/styles.css';
410
+
411
+ @tailwind base;
412
+ @tailwind components;
413
+ @tailwind utilities;
414
+ ```
415
+
416
+ **Nuxt**
417
+
418
+ Nuxt reads PostCSS plugins from `postcss.plugins` in `nuxt.config.ts`, in
419
+ the order listed:
420
+
421
+ ```ts title="nuxt.config.ts"
422
+ import { hosted } from 'c15t/vue';
423
+
424
+ export default defineNuxtConfig({
425
+ c15t: { backendURL: '/api/c15t', mode: hosted() },
426
+ compatibilityDate: '2026-07-04',
427
+ css: ['~/assets/css/main.css'],
428
+ modules: ['c15t/vue'],
429
+ postcss: {
430
+ plugins: {
431
+ 'c15t/postcss-tailwind3': {},
432
+ tailwindcss: {},
433
+ autoprefixer: {},
434
+ },
435
+ },
436
+ ssr: false,
437
+ });
438
+ ```
439
+
440
+ Scan `app/` and turn on the class-based dark variant:
441
+
442
+ ```ts title="tailwind.config.ts"
443
+ import type { Config } from 'tailwindcss';
444
+
445
+ export default {
446
+ content: ['./app/**/*.{vue,ts}'],
447
+ darkMode: 'class',
448
+ } satisfies Config;
449
+ ```
450
+
451
+ The Vue components load c15t's styles themselves, and the plugin processes
452
+ them too, so the CSS entry holds only the directives:
453
+
454
+ ```css title="app/assets/css/main.css"
455
+ @tailwind base;
456
+ @tailwind components;
457
+ @tailwind utilities;
458
+ ```
459
+
460
+ **Vue**
461
+
462
+ ```js title="postcss.config.mjs"
463
+ export default {
464
+ plugins: { 'c15t/postcss-tailwind3': {}, tailwindcss: {}, autoprefixer: {} },
465
+ };
466
+ ```
467
+
468
+ Scan your source and turn on the class-based dark variant:
469
+
470
+ ```ts title="tailwind.config.ts"
471
+ import type { Config } from 'tailwindcss';
472
+
473
+ export default {
474
+ content: ['./index.html', './src/**/*.{vue,ts}'],
475
+ darkMode: 'class',
476
+ } satisfies Config;
477
+ ```
478
+
479
+ The Vue components load their own stylesheets, and the plugin processes
480
+ them too, so the CSS entry holds only the directives:
481
+
482
+ ```css title="src/style.css"
483
+ @tailwind base;
484
+ @tailwind components;
485
+ @tailwind utilities;
486
+ ```
487
+
488
+ **Astro**
489
+
490
+ ```js title="postcss.config.mjs"
491
+ export default {
492
+ plugins: { 'c15t/postcss-tailwind3': {}, tailwindcss: {}, autoprefixer: {} },
493
+ };
494
+ ```
495
+
496
+ Scan your source and turn on the class-based dark variant:
497
+
498
+ ```ts title="tailwind.config.ts"
499
+ import type { Config } from 'tailwindcss';
500
+
501
+ export default {
502
+ content: ['./src/**/*.{astro,html,ts}'],
503
+ darkMode: 'class',
504
+ } satisfies Config;
505
+ ```
506
+
507
+ When the integration finds Tailwind 3 in the project, it adds
508
+ `c15t/astro/styles.css` to every page through Astro's CSS pipeline
509
+ instead of inlining the banner's rules, so the plugin processes it. You
510
+ do not set `styles: false` or import c15t's stylesheet, and the CSS
511
+ entry holds only the directives. The first paint still waits for that
512
+ stylesheet:
513
+
514
+ ```css title="src/styles/global.css"
515
+ @tailwind base;
516
+ @tailwind components;
517
+ @tailwind utilities;
518
+ ```
519
+
520
+ **Svelte**
521
+
522
+ ```js title="postcss.config.mjs"
523
+ export default {
524
+ plugins: {
525
+ '@c15t/svelte/postcss-tailwind3': {},
526
+ tailwindcss: {},
527
+ autoprefixer: {},
528
+ },
529
+ };
530
+ ```
531
+
532
+ Scan your source and turn on the class-based dark variant:
533
+
534
+ ```ts title="tailwind.config.ts"
535
+ import type { Config } from 'tailwindcss';
536
+
537
+ export default {
538
+ content: ['./index.html', './src/**/*.{svelte,ts}'],
539
+ darkMode: 'class',
540
+ } satisfies Config;
541
+ ```
542
+
543
+ Import `@c15t/svelte/styles.css` above the directives, import this
544
+ stylesheet from `src/main.ts`, and pass `styles={false}` to
545
+ `ConsentProvider`:
546
+
547
+ ```css title="src/app.css"
548
+ /* Vite ignores an @import below other rules, so it goes first. */
549
+ @import '@c15t/svelte/styles.css';
550
+
551
+ @tailwind base;
552
+ @tailwind components;
553
+ @tailwind utilities;
554
+ ```
555
+
556
+ **SvelteKit**
557
+
558
+ ```js title="postcss.config.mjs"
559
+ export default {
560
+ plugins: {
561
+ '@c15t/svelte/postcss-tailwind3': {},
562
+ tailwindcss: {},
563
+ autoprefixer: {},
564
+ },
565
+ };
566
+ ```
567
+
568
+ Scan your source and turn on the class-based dark variant:
569
+
570
+ ```ts title="tailwind.config.ts"
571
+ import type { Config } from 'tailwindcss';
572
+
573
+ export default {
574
+ content: ['./src/**/*.{html,svelte,ts}'],
575
+ darkMode: 'class',
576
+ } satisfies Config;
577
+ ```
578
+
579
+ Import `@c15t/svelte/styles.css` above the directives, import this
580
+ stylesheet from your root `+layout.svelte`, and pass `styles={false}` to
581
+ `ConsentRoot`:
582
+
583
+ ```css title="src/app.css"
584
+ /* Vite ignores an @import below other rules, so it goes first. */
585
+ @import '@c15t/svelte/styles.css';
586
+
587
+ @tailwind base;
588
+ @tailwind components;
589
+ @tailwind utilities;
590
+ ```
591
+
592
+ **HTML**
593
+
594
+ In the default shadow root, c15t's stylesheet never meets Tailwind, so the
595
+ page's Tailwind 3 setup needs nothing from c15t:
596
+
597
+ ```css title="style.css"
598
+ @tailwind base;
599
+ @tailwind components;
600
+ @tailwind utilities;
601
+ ```
602
+
603
+ To render the UI in the page instead, see
604
+ [render the UI in the light DOM](#render-the-ui-in-the-light-dom).
605
+
606
+ **JavaScript**
607
+
608
+ `init()` renders into a shadow root by default, where c15t's stylesheet
609
+ never meets Tailwind. To render the UI in the page and build c15t's rules
610
+ into your Tailwind CSS, see
611
+ [render the UI in the light DOM](#render-the-ui-in-the-light-dom).
612
+
613
+ ## Put utilities on c15t parts
614
+
615
+ Pass utilities to a component part through your framework's part API. The
616
+ fixtures put padding on the banner root, which c15t also pads, with a different
617
+ value in dark mode. On Tailwind 4 a plain utility wins. On Tailwind 3, add `!`,
618
+ as in `!p-[7px] dark:!p-[11px]`, because c15t's unlayered rules outrank a plain
619
+ utility. [Component parts](./slots.md) lists the parts each
620
+ framework exposes.
621
+
622
+ Tailwind only generates classes it finds in the files its `content` globs or
623
+ `@source` rules scan. Keep part classes in a scanned file.
624
+
625
+ **Next.js**
626
+
627
+ Add the classes to `options.components` on `ConsentRoot`, in the
628
+ `'use client'` wrapper from your quickstart:
629
+
630
+ ```tsx title="app/consent.tsx"
631
+ options={{
632
+ components: {
633
+ banner: {
634
+ root: { className: 'p-[7px] dark:p-[11px]' },
635
+ },
636
+ },
637
+ mode,
638
+ }}
639
+ ```
640
+
641
+ **TanStack Start**
642
+
643
+ ```tsx title="src/routes/__root.tsx"
644
+ options={{
645
+ components: {
646
+ banner: {
647
+ root: { className: 'p-[7px] dark:p-[11px]' },
648
+ },
649
+ },
650
+ mode,
651
+ }}
652
+ ```
653
+
654
+ **React**
655
+
656
+ ```tsx title="src/main.tsx"
657
+ const options = {
658
+ components: { banner: { root: { className: 'p-[7px] dark:p-[11px]' } } },
659
+ mode,
660
+ };
661
+ ```
662
+
663
+ **Nuxt**
664
+
665
+ Tailwind scans `app/`, not `nuxt.config.ts`, so put part classes in
666
+ `app/app.config.ts` under the `c15t` key. The module merges it with the
667
+ `c15t` options in `nuxt.config.ts`. Vue takes `class`, not `className`:
668
+
669
+ ```ts title="app/app.config.ts"
670
+ // Tailwind scans `app/`, so keep slot classes here rather than in
671
+ // nuxt.config.ts.
672
+ export default defineAppConfig({
673
+ c15t: {
674
+ components: { banner: { root: { class: 'p-[7px] dark:p-[11px]' } } },
675
+ },
676
+ });
677
+ ```
678
+
679
+ **Vue**
680
+
681
+ Add the classes to `components` in the `c15tVue` options. Vue takes
682
+ `class`, not `className`:
683
+
684
+ ```ts title="src/main.ts"
685
+ .use(c15tVue, {
686
+ components: {
687
+ banner: {
688
+ root: { class: 'p-[7px] dark:p-[11px]' },
689
+ },
690
+ },
691
+ mode: hosted(),
692
+ })
693
+ ```
694
+
695
+ **Astro**
696
+
697
+ `class` on `ConsentBanner` goes on the banner root:
698
+
699
+ ```astro title="src/pages/index.astro"
700
+ <ConsentBanner class="p-[7px] dark:p-[11px]" />
701
+ ```
702
+
703
+ **Svelte**
704
+
705
+ `class` on `ConsentBanner` goes on the banner root:
706
+
707
+ ```svelte title="src/App.svelte"
708
+ <ConsentBanner class="p-[7px] dark:p-[11px]" />
709
+ ```
710
+
711
+ **SvelteKit**
712
+
713
+ ```svelte title="src/routes/+layout.svelte"
714
+ <ConsentBanner class="p-[7px] dark:p-[11px]" />
715
+ ```
716
+
717
+ **HTML**
718
+
719
+ Put the classes on parts with `ui.theme.slots`, and link your Tailwind
720
+ build into the shadow root with `ui.stylesheetURLs`. Keep the page's own
721
+ link too. Tailwind 4 registers some of its variables with `@property`,
722
+ which only takes effect in the page's stylesheets, not a shadow root's:
723
+
724
+ ```html title="index.html"
725
+ <link
726
+ rel="stylesheet"
727
+ href="/tailwind.css"
728
+ />
729
+ <script>
730
+ window.c15t = window.c15t || [];
731
+ c15t.push([
732
+ 'config',
733
+ {
734
+ ui: {
735
+ // The banner renders in a shadow root, where the page's
736
+ // stylesheets do not reach. Link your Tailwind build into it
737
+ // too, and keep the page's own link: Tailwind 4 registers
738
+ // variables with @property, which only works in the page.
739
+ stylesheetURLs: ['/tailwind.css'],
740
+ theme: {
741
+ slots: {
742
+ consentBannerCard: 'rounded-none border-4 border-sky-600',
743
+ consentBannerTitle: 'uppercase tracking-wide',
744
+ },
745
+ },
746
+ },
747
+ },
748
+ ]);
749
+ </script>
750
+ ```
751
+
752
+ Tailwind must scan the file that holds the slot classes.
753
+
754
+ **JavaScript**
755
+
756
+ Pass `ui.stylesheetURLs` and `ui.theme.slots` to `init()`. Keep a link to
757
+ the same stylesheet on the page, because Tailwind 4's `@property` rules
758
+ only take effect there:
759
+
760
+ ```ts title="src/consent.ts (partial)"
761
+ ui: {
762
+ stylesheetURLs: ['/tailwind.css'],
763
+ theme: {
764
+ slots: {
765
+ consentBannerCard: 'rounded-none border-4 border-sky-600',
766
+ },
767
+ },
768
+ },
769
+ ```
770
+
771
+ ## Use the dark variant
772
+
773
+ The fixtures make Tailwind's `dark:` variant follow a `dark` class on `<html>`:
774
+ `@custom-variant dark (&:where(.dark, .dark *));` on Tailwind 4 and
775
+ `darkMode: 'class'` on Tailwind 3. c15t's stylesheet reads the same class, and
776
+ in React, Next.js, TanStack Start, Vue, Nuxt, Svelte and SvelteKit an unset
777
+ `colorScheme` also copies it into `c15t-dark`. One toggle then switches your
778
+ utilities and c15t's dark tokens together.
779
+
780
+ Astro and the script tag follow the system setting by default. [Dark mode](./dark-mode.md) covers each
781
+ case.
782
+
783
+ ## Render the UI in the light DOM
784
+
785
+ The script tag and `init()` render into a shadow root, so your page's CSS does
786
+ not reach c15t and c15t's CSS does not reach your page. To style the UI with
787
+ your page's Tailwind build directly, render it in the page with
788
+ `data-shadow="false"` or `ui: { shadow: false }`.
789
+
790
+ On Tailwind 4, that is the whole change. c15t still injects its layered
791
+ stylesheet, and the layer order keeps it above preflight:
792
+
793
+ ```html title="light-dom.html"
794
+ <script
795
+ src="/c15t.offline.js"
796
+ data-mode="offline"
797
+ data-country="DE"
798
+ data-shadow="false"
799
+ defer
800
+ ></script>
801
+ ```
802
+
803
+ On Tailwind 3, keep the default shadow root. Tailwind 3's preflight is
804
+ unlayered, so in the page it beats c15t's layered rules whatever their
805
+ specificity and removes the button padding and card borders. Linking
806
+ `c15t.css` from the page does not help, because nothing removes its layers.
807
+
808
+ To render in the light DOM anyway, turn the injected sheet off with
809
+ `styles: false`, and build c15t's rules into your Tailwind CSS with the plugin
810
+ instead:
811
+
812
+ ```html title="light-dom.html"
813
+ <script>
814
+ window.c15t = [['config', { ui: { shadow: false, styles: false } }]];
815
+ </script>
816
+ <script
817
+ src="/c15t.offline.js"
818
+ data-mode="offline"
819
+ data-country="DE"
820
+ defer
821
+ ></script>
822
+ ```
823
+
824
+ Import `@c15t/browser/styles.css` above the directives in your Tailwind entry.
825
+ Install `@c15t/browser@alpha`, which provides both the stylesheet and
826
+ `@c15t/browser/postcss-tailwind3`:
827
+
828
+ ```css title="style.css"
829
+ /*
830
+ * With `shadow: false`, c15t's injected stylesheet is layered and Tailwind
831
+ * 3's preflight is not, so preflight wins. Turn the injected sheet off and
832
+ * build c15t's rules into your Tailwind CSS instead.
833
+ */
834
+ @import '@c15t/browser/styles.css';
835
+
836
+ @tailwind base;
837
+ @tailwind components;
838
+ @tailwind utilities;
839
+ ```
840
+
841
+ ```js title="postcss.config.mjs"
842
+ export default {
843
+ plugins: {
844
+ '@c15t/browser/postcss-tailwind3': {},
845
+ tailwindcss: {},
846
+ autoprefixer: {},
847
+ },
848
+ };
849
+ ```
850
+
851
+ In the light DOM your page's global rules reach the banner too, so check
852
+ buttons and headings after the switch.
853
+
854
+ ## Check the result
855
+
856
+ 1. Build the app and open it in a private window. The banner has its card
857
+ background, border and button padding, so preflight did not reset it.
858
+ 2. Inspect the part you gave a utility. In the Styles panel, your utility is
859
+ applied and c15t's rule for the same property is struck out.
860
+ 3. Add the `dark` class to `<html>`. Your `dark:` utility applies and, where
861
+ c15t follows the class, the banner switches to dark colors.
862
+ 4. Open the preference dialog. Its rules come from a separate stylesheet in
863
+ most frameworks, so check that it is styled too.