@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
@@ -1,55 +1,237 @@
1
1
  ---
2
- title: Style component slots
3
- description: Target a specific c15t component part without replacing its markup or behavior.
2
+ title: Component parts
3
+ description: Find every part of c15t's banner, dialog, widget, trigger and
4
+ ConsentGate placeholder, its key in your framework's part API, and the data
5
+ attributes to select on.
4
6
  group: customization
5
7
  ---
6
8
 
7
- ## Use slots for local changes
9
+ ## Which part API your framework uses
8
10
 
9
- In React and Next.js, put per-part attributes in `options.components`. This
10
- fragment belongs in an existing provider's options:
11
+ Each framework has one way to add classes, inline styles or attributes to a
12
+ single part of a stock component. The keys differ between the two
13
+ vocabularies, so a configuration from one does not work in the other.
14
+
15
+ | Framework | Part API | Keys look like | Class key |
16
+ | ----------------------- | ------------------------------------------------------------------------ | ------------------------- | ------------------------ |
17
+ | Next.js, TanStack Start | `options.components` in Next.js `c15t.config.ts`, or on `ConsentRoot` | `components.banner.card` | `className` |
18
+ | React | `components` in the `ConsentProvider` options | `components.banner.card` | `className` |
19
+ | Nuxt | `components` in the `c15t` options, or in `app/app.config.ts` | `components.banner.card` | `class` |
20
+ | Vue | `components` in the `c15tVue` options | `components.banner.card` | `class` |
21
+ | Astro | `theme.slots` in the `c15t()` integration options | `slots.consentBannerCard` | A string, or `className` |
22
+ | Svelte, SvelteKit | `theme.slots` on `ConsentProvider` (Svelte) or `ConsentRoot` (SvelteKit) | `slots.consentBannerCard` | A string, or `className` |
23
+ | HTML, JavaScript | `ui.theme.slots` | `slots.consentBannerCard` | A string, or `className` |
24
+
25
+ React and Vue also read `theme.slots` from the theme in their options, and
26
+ apply each slot to the matching `components` part, such as
27
+ `consentDialogCard` to `dialog.card` and `toggle` to `switch.root`. Where both
28
+ set the same part, classes from both apply, inline styles merge with
29
+ `components` winning per property, and any other attribute in `components`
30
+ replaces the theme's. In Vue and Nuxt, each part object is bound with
31
+ `v-bind`, so write `class` and `style` rather than React's `className`.
32
+
33
+ Svelte's stock components, and Astro's `ConsentBanner`, `IABConsentBanner`
34
+ and `ConsentDialogTrigger`, also take a `class` prop. On `ConsentBanner` it
35
+ goes on the banner root.
36
+
37
+ This React fragment belongs in the provider options:
11
38
 
12
39
  ```tsx
13
40
  components: {
14
41
  banner: {
15
- card: { className: 'rounded-none shadow-none' },
16
- title: { className: 'font-semibold' },
17
- footer: { className: 'border-t' },
42
+ card: { className: 'brand-card' },
43
+ title: { style: { fontWeight: 600 } },
18
44
  },
45
+ },
46
+ ```
47
+
48
+ The same parts with `theme.slots`, which every framework reads:
49
+
50
+ ```ts
51
+ theme: {
52
+ slots: {
53
+ consentBannerCard: 'brand-card',
54
+ consentBannerTitle: 'brand-title',
55
+ },
56
+ },
57
+ ```
58
+
59
+ A slot can also be `{ className, style }`. Svelte applies both on every part,
60
+ including the IAB banner and dialog.
61
+
62
+ [Class names and CSS-in-JS](./class-names.md) covers CSS
63
+ Modules, vanilla-extract, StyleX and Emotion, and
64
+ [Tailwind CSS](./tailwind.md) covers utilities on parts.
65
+
66
+ ## Banner parts
67
+
68
+ | Part | `components` key | `theme.slots` key | `data-testid` |
69
+ | ------------------------------------------- | ------------------------------------ | ---------------------------------- | --------------------- |
70
+ | Positioning root, with the state attributes | `banner.root` | `consentBanner` | `consent-banner-root` |
71
+ | Card sizing and branding container | `banner.cardShell` | None | |
72
+ | Visible card | `banner.card` | `consentBannerCard` | `consent-banner-card` |
73
+ | Title and description container | `banner.header` | `consentBannerHeader` | |
74
+ | Title | `banner.title` | `consentBannerTitle` | |
75
+ | Description | `description.banner` | `consentBannerDescription` | |
76
+ | Action area | `banner.footer` | `consentBannerFooter` | |
77
+ | Group of action groups | `banner.actions` | None | |
78
+ | One group of equally prominent actions | `banner.actionGroup` | `consentBannerFooterSubGroup` | |
79
+ | Group of right links | `banner.rights` | `consentBannerRights` | |
80
+ | One right link | `banner.rightLink` | `consentBannerRightLink` | |
81
+ | Backdrop of a blocking banner | `banner.overlay` | `consentBannerOverlay` | |
82
+ | "Secured by" tag | `tag.banner` | `consentBannerTag` | |
83
+ | Filled and outlined buttons | `button.primary`, `button.secondary` | `buttonPrimary`, `buttonSecondary` | |
84
+
85
+ The button parts apply to every c15t button of that style, in the banner and
86
+ the dialog. The script tag's banner has no rights group, so
87
+ `consentBannerRights` does not apply there.
88
+
89
+ ## Preference dialog parts
90
+
91
+ | Part | `components` key | `theme.slots` key | `data-testid` |
92
+ | ---------------- | -------------------- | -------------------------- | --------------------- |
93
+ | Positioner | `dialog.root` | None | |
94
+ | Dialog container | `dialog.container` | `consentDialog` | `consent-dialog-root` |
95
+ | Card | `dialog.card` | `consentDialogCard` | |
96
+ | Header | `dialog.header` | `consentDialogHeader` | |
97
+ | Title | `dialog.title` | `consentDialogTitle` | |
98
+ | Description | `description.dialog` | `consentDialogDescription` | |
99
+ | Content | `dialog.content` | `consentDialogContent` | |
100
+ | Backdrop | `dialog.overlay` | `consentDialogOverlay` | |
101
+ | "Secured by" tag | `tag.dialog` | `consentDialogTag` | |
102
+
103
+ The stock dialog's footer is the preference widget's footer. Style it with
104
+ `consentWidgetFooter`. There is no `consentDialogFooter` slot.
105
+
106
+ ## Preference widget parts
107
+
108
+ The widget is the list of categories inside the dialog. React and Vue call it
109
+ `manager`.
110
+
111
+ | Part | `components` key | `theme.slots` key |
112
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
113
+ | Widget root | `manager.root` | `consentWidget` |
114
+ | Footer | `manager.footer` | `consentWidgetFooter` |
115
+ | Group of action groups | `manager.actions` | None |
116
+ | One action group | `manager.actionGroup` | `consentWidgetFooterSubGroup` |
117
+ | Category accordion | `accordion.root`, `accordion.triggerRow`, `accordion.arrow`, `accordion.header`, `accordion.title`, `accordion.control`, `accordion.contentViewport`, `accordion.contentInner` | `consentWidgetAccordion` |
118
+ | One accordion item | `accordion-item.root`, `accordion-item.trigger`, `accordion-item.content` | None |
119
+ | Category switch | `switch.root`, `switch.track`, `switch.thumb` | `toggle` |
120
+ | Vendor list | `vendor-list.root`, `vendor-list.trigger`, `vendor-list.content`, `vendor-list.item`, `vendor-list.header`, `vendor-list.name`, `vendor-list.description`, `vendor-list.link`, `vendor-list.control` | None |
121
+ | "Secured by" tag | `tag.manager` in React, `tag.dialog` in Vue | `consentWidgetTag` |
122
+
123
+ ## Floating trigger parts
124
+
125
+ | Part | `components` key | `theme.slots` key |
126
+ | ---------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
127
+ | Button | `trigger.root` | `consentDialogTrigger` |
128
+ | Icon | `trigger.icon` | `consentDialogTriggerIcon` |
129
+ | Label | `trigger.text` | None |
130
+ | Toolbar, its items and icons | `trigger.toolbar`, `trigger.toolbarItem`, `trigger.toolbarIcon` | `consentDialogTriggerToolbar`, `consentDialogTriggerToolbarItem`, `consentDialogTriggerToolbarIcon` |
131
+
132
+ React renders the toolbar from `ConsentDialogTriggerToolbar`, and while
133
+ `ConsentDevTools` is mounted. Vue renders it only while `ConsentDevTools` is
134
+ mounted. In Astro, the toolbar slots reach the React dialog.
135
+
136
+ ## Legal links and IAB TCF parts
137
+
138
+ | Component | `components` keys | `theme.slots` keys |
139
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
140
+ | Legal links | `legal-links.root`, and `link.banner`, `link.dialog`, `link.manager` for one link | None |
141
+ | IAB banner | `iab-banner.root`, `cardShell`, `card`, `header`, `title`, `description`, `partnersLink`, `purposeList`, `purposeMore`, `legitimateInterestNotice`, `footer`, `actions`, `actionGroup`, `overlay` | `iabConsentBanner`, `iabConsentBannerCard`, `iabConsentBannerHeader`, `iabConsentBannerFooter`, `iabConsentBannerTag`, `iabConsentBannerOverlay` |
142
+ | IAB dialog | `iab-dialog.root`, `card`, `header`, `headerContent`, `title`, `description`, `closeButton`, `body`, `content`, `loading`, `footer`, `tabs`, `tabsList`, `tabTrigger`, `tabIndicator`, `tabPanel`, `specialPurposes`, `consentNotice`, `actions`, `actionGroup`, `overlay` | `iabConsentDialog`, `iabConsentDialogCard`, `iabConsentDialogHeader`, `iabConsentDialogFooter`, `iabConsentDialogTag`, `iabConsentDialogOverlay` |
143
+ | IAB purpose, stack and vendor rows | `iab-purpose-item.*`, `iab-stack-item.*`, `iab-vendor-list.*` | None |
144
+
145
+ Legal links take no `theme.slots` key. They keep their stock link class, and
146
+ a description slot's classes stay on the description around them.
147
+
148
+ ## ConsentGate placeholder parts
149
+
150
+ `ConsentGate` shows a placeholder card while its category is denied. React,
151
+ Next.js, TanStack Start, Vue, Nuxt, Svelte and SvelteKit render the same
152
+ three parts:
153
+
154
+ | Part | `components` key | `theme.slots` key | `data-testid` |
155
+ | ----------------------------- | --------------------- | ------------------- | -------------------------- |
156
+ | Placeholder card | `consent-gate.root` | `consentGate` | `consent-gate-placeholder` |
157
+ | Title | `consent-gate.title` | `consentGateTitle` | `consent-gate-title` |
158
+ | Button that opens preferences | `consent-gate.button` | `consentGateButton` | `consent-gate-button` |
159
+
160
+ The button part applies on top of `button.primary`, or `buttonPrimary`. The
161
+ parts only reach the built-in placeholder. A placeholder you pass yourself
162
+ takes your own classes, and the wrapper around the gate takes `className` in
163
+ React or `class` in Svelte. Astro, HTML and JavaScript have no `ConsentGate`.
164
+
165
+ ## Style parts from outside the script tag's shadow root
166
+
167
+ The script tag and `init()` render into a shadow root. Every part that has a
168
+ `theme.slots` key carries it in a `part` attribute, so page CSS can reach it
169
+ with `::part()`:
170
+
171
+ ```css
172
+ [data-c15t-ui]::part(consentBannerCard) {
173
+ border: 3px solid #6943a3;
19
174
  }
20
175
  ```
21
176
 
22
- The class names above assume Tailwind. A slot can also receive `style` and other
23
- supported element attributes. Keep shared colors and radius scales in tokens;
24
- use slots when only one component part should change.
177
+ ## Select on state attributes
178
+
179
+ Parts carry `data-*` attributes that describe their state. Select on these
180
+ instead of guessing at markup:
181
+
182
+ | Element | Attributes |
183
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
184
+ | Banner root | `data-prompt`, `data-model`, `data-variant`, `data-position`, `data-blocking` |
185
+ | Action buttons | `data-action` (`accept`, `reject`, `customize`, `dismiss` or `save`), `data-variant`, `data-mode` |
186
+ | Footer and action groups | `data-direction`, `data-fill`, `data-split` |
187
+ | Right links | `data-action="right"`, `data-right` |
188
+ | Preference dialog | `data-state` (`open` or `closed`), on the elements listed in [motion](./motion.md#animate-your-own-rules-on-dialog-state) |
189
+ | Category switch | `data-state`, `data-disabled` |
190
+
191
+ The script tag's banner root has `data-variant`, `data-position` and
192
+ `data-blocking` only, with `data-blocking` set to `"true"` or `"false"`. Its
193
+ right links carry `data-action="customize"`.
194
+
195
+ The banner card does not inherit the root's attributes. With Tailwind, give
196
+ the root `group` and read the root's attribute from a child part:
197
+
198
+ ```tsx
199
+ components: {
200
+ banner: {
201
+ root: { className: 'group' },
202
+ card: { className: 'group-data-[variant=bar]:rounded-none' },
203
+ },
204
+ },
205
+ ```
25
206
 
26
- ## Read attributes on the right element
207
+ Test notices as well as choice prompts. A notice has an acknowledge action,
208
+ `data-action="dismiss"`, instead of accept and reject.
27
209
 
28
- The banner root carries `data-prompt`, `data-model`, `data-variant`,
29
- `data-position` and `data-blocking`. Its child card does not inherit those HTML
30
- attributes. In Tailwind, give the root `className: 'group'` and use
31
- `group-data-[variant=bar]:...` on a child slot.
210
+ ## Do not target c15t's class names
32
211
 
33
- | React banner slot | Use |
34
- | ---------------------------------- | ------------------------------------- |
35
- | `root` | Position wrapper and state attributes |
36
- | `cardShell` | Card sizing and branding container |
37
- | `card` | Visible card |
38
- | `header`, `title`, `description` | Heading and explanatory copy |
39
- | `footer`, `actions`, `actionGroup` | Action layout |
40
- | `rights`, `rightLink` | Preferences access controls |
41
- | `overlay` | Backdrop for blocking presentation |
212
+ c15t's stock class names are generated from CSS Modules and end in a hash, such
213
+ as `c15t-ui-card-lgjVq`. The hash changes whenever the source CSS changes, and
214
+ the classes disappear under `noStyle`. A rule that targets one breaks on an
215
+ upgrade without warning. Target a part API, `data-testid`, a `data-*`
216
+ attribute or `::part()` instead.
42
217
 
43
- Buttons expose `data-action` for action-specific CSS. Test notices as well as
44
- choice prompts; a notice uses acknowledgement rather than accept/reject.
218
+ ## Remove c15t's classes with noStyle
45
219
 
46
- ## When to remove styles
220
+ `noStyle` renders the same markup and behavior without c15t's stock classes. It
221
+ keeps your part classes and styles, `data-testid` and the `data-*` attributes.
222
+ It does not replace layout, spacing, focus indicators or responsive behavior,
223
+ so use it when you intend to write all of that yourself.
47
224
 
48
- `noStyle` removes the built-in component styling. It does not supply replacement
49
- layout, spacing, focus indicators or responsive behavior. Use it when you intend
50
- to own all of that work, not as the first response to a token that appears to do
51
- nothing.
225
+ | Framework | Where |
226
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
227
+ | Next.js, TanStack Start, React | `noStyle` in the provider options for every component, or the `noStyle` prop on `ConsentBanner`, `ConsentDialog`, `ConsentWidget`, `ConsentDialogTrigger` and the IAB components |
228
+ | Svelte, SvelteKit | `noStyle` in the provider options, or the prop on a stock component |
229
+ | Astro | `noStyle` prop on `ConsentBanner` and `IABConsentBanner` |
230
+ | HTML, JavaScript | `ui.noStyle`, which also drops the bundled stylesheet |
231
+ | Vue, Nuxt | The `noStyle` prop on `ConsentWidget`, and on the `PreferenceItemRoot` and `PreferenceItemContent` primitives, whose other parts follow the root. The banner, dialog and trigger have no `noStyle` |
52
232
 
53
- If the markup itself must change, use the adapter's compound components or
54
- headless API. The slot objects above are the React contract; check Vue and Svelte
55
- slot types before reusing them.
233
+ In `theme.slots`, `{ noStyle: true }` on one slot replaces that part's stock
234
+ classes in Svelte, Astro's banner and the script tag. React and Vue, including
235
+ Astro's React and Vue dialog islands, ignore a slot's `noStyle`, so its classes
236
+ apply on top of the stock ones. If the markup itself must change, use your framework's compound
237
+ components or headless API.
@@ -0,0 +1,248 @@
1
+ ---
2
+ title: Stylesheets and CSS layers
3
+ description: See how c15t delivers its styles in each framework without a
4
+ render-blocking stylesheet, when to import styles.css yourself with styles
5
+ false, which file holds the dialog's rules, and how c15t's cascade layer meets
6
+ your own.
7
+ group: customization
8
+ ---
9
+
10
+ ## What each framework loads
11
+
12
+ | Framework | What you import | How the styles arrive |
13
+ | ------------------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
14
+ | Next.js, TanStack Start, React | Nothing | Each stock surface renders the rules it uses as `<style>` elements |
15
+ | Nuxt, Vue | Nothing | Each Vue component imports its own stylesheet |
16
+ | Astro | Nothing | `<ConsentScript />` inlines the banner's rules into the HTML. The client links the dialog's rules when a dialog first opens. On a Tailwind CSS 3 site, the integration adds `c15t/astro/styles.css` to every page instead |
17
+ | Svelte | Nothing | Each stock surface inserts the rules it uses into `<head>` |
18
+ | SvelteKit | Nothing | `c15tHandle` writes a server-rendered banner's rules into the HTML. The other surfaces insert theirs in the browser |
19
+ | HTML | Nothing | `c15t.js` carries its stylesheet into the UI's shadow root |
20
+ | JavaScript | Nothing | `init()` carries its stylesheet into the UI's shadow root |
21
+
22
+ Inline c15t styles avoid a stylesheet request before the page's first paint.
23
+ A linked stylesheet in `<head>` used to delay it by a round trip. With 4x
24
+ CPU throttling, 1.6 Mbps download and 150 ms RTT, a Next.js page first painted
25
+ at about 370 ms instead of 650 ms once the link was gone.
26
+
27
+ Inline rules add bytes to each server-rendered HTML response. Enable HTTP
28
+ compression on the production host to reduce their transfer cost. On repeat
29
+ document visits, a cached external stylesheet can paint sooner than sending
30
+ the inline rules again. To use that cache, keep the stylesheet imports and
31
+ set `styles: false` as described below.
32
+
33
+ Load `styles.css` yourself with Tailwind CSS 3 or a named cascade layer.
34
+ [Import the stylesheet yourself](#import-the-stylesheet-yourself)
35
+ covers those cases.
36
+
37
+ ## How the surfaces deliver their rules
38
+
39
+ c15t splits its rules into two sheets. The first-paint sheet holds the
40
+ default tokens, every c15t CSS variable, and the rules for the banner, the
41
+ floating trigger and the `ConsentGate` placeholder. The dialog sheet holds the
42
+ preference dialog's and the preference widget's rules.
43
+
44
+ In React, Next.js and TanStack Start, `ConsentBanner`, `ConsentDialogTrigger`
45
+ and the default `ConsentGate` placeholder render the first-paint sheet.
46
+ `ConsentDialog` and `ConsentWidget` render it plus the dialog sheet. The
47
+ dialog sheet ships with the dialog's lazily loaded code, so it is not part of
48
+ the first page load. A server-rendered banner puts its rules in the HTML.
49
+
50
+ `IABConsentBanner` also delivers the IAB variables and banner rules.
51
+ `IABConsentDialog` adds the IAB dialog rules when it opens, including the
52
+ shared rules it needs when rendered without a banner. IAB setups need no
53
+ stylesheet imports with automatic styling enabled.
54
+
55
+ Streamed React IAB banners become visible once their complete card markup
56
+ arrives. This prevents the centered card from moving as the browser parses
57
+ its remaining content, without waiting for hydration.
58
+
59
+ * In React 19, React moves the elements into `<head>` and renders each sheet
60
+ once per page, as `<style data-precedence="c15t" data-href="c15t-first-paint">`.
61
+ * In React 18, the elements render in place, next to the surface.
62
+ * In React 19 with the provider's `nonce` option set, they also render in
63
+ place and carry the nonce. React drops the nonce of a style it moves to
64
+ `<head>` unless the app passed that nonce to React's server renderer.
65
+
66
+ In Svelte, each stock surface inserts the sheets it uses into `<head>` as
67
+ `<style data-c15t-styles="…">`, once per page, before its own elements
68
+ render. The elements stay after the surface unmounts. The Svelte dialog's
69
+ sheets, its rules and the primitives, load with the dialog's code.
70
+
71
+ On a server-rendered SvelteKit page, the banner leaves a
72
+ `<meta name="c15t-styles">` marker, and `c15tHandle` from `@c15t/svelte/kit`
73
+ writes the sheets into the HTML `<head>` as `<style>` elements. The banner is
74
+ styled before hydration with no stylesheet request. Without `c15tHandle` in
75
+ `src/hooks.server.ts`, a server-rendered banner shows unstyled until
76
+ hydration. The [SvelteKit quickstart](https://v3.c15t.com/docs/frameworks/sveltekit/quickstart)
77
+ adds the handle.
78
+
79
+ In Astro, `<ConsentScript />`, or the banner on a layout without it, inlines
80
+ the first-paint sheet into the HTML as
81
+ `<style data-c15t-styles="c15t-first-paint">` with the page nonce. When
82
+ `tailwindcss` resolves to version 3 from the Astro root, the integration
83
+ inlines nothing and adds `c15t/astro/styles.css` to every page through
84
+ Astro's CSS pipeline, so the site's `c15t/postcss-tailwind3` plugin processes
85
+ it. That stylesheet still holds back the first paint.
86
+
87
+ The surfaces render no stylesheet with `noStyle`, or when the provider sets
88
+ `styles: false`.
89
+
90
+ ## Import the stylesheet yourself
91
+
92
+ Set `styles: false` in the provider options and import `styles.css` when you
93
+ need control over the file:
94
+
95
+ * **Tailwind CSS 3.** c15t's `<style>` rules sit in a native
96
+ `@layer components`, and Tailwind 3's unlayered preflight beats them. Import
97
+ `styles.css` through the `postcss-tailwind3` plugin instead, as
98
+ [Tailwind CSS](./tailwind.md#set-up-tailwind-css-3) shows.
99
+ Astro sites skip this: the integration detects Tailwind 3 and links the
100
+ stylesheet itself.
101
+ * **A named cascade layer.** Import the stylesheet into your own layer, as in
102
+ [order c15t's layer against your CSS](#order-c15ts-layer-against-your-css).
103
+ * **Cached styles across document visits.** Keep external CSS when its HTTP
104
+ cache performs better for your site's repeat visits. Compare cold and warm
105
+ visits on your production host before choosing this option.
106
+
107
+ | Framework | Option | Files to import |
108
+ | ----------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------- |
109
+ | Next.js | `options.styles` in `c15t.config.ts` or on `ConsentRoot` | `c15t/next/styles.css`, and `c15t/next/iab/styles.css` for IAB TCF |
110
+ | TanStack Start | `options.styles` on `ConsentRoot` | `c15t/tanstack-start/styles.css`, and `c15t/tanstack-start/iab/styles.css` for IAB TCF |
111
+ | React | `options.styles` on `ConsentProvider` | `c15t/react/styles.css`, and `c15t/react/iab/styles.css` for IAB TCF |
112
+ | Svelte, SvelteKit | `options.styles` on `ConsentProvider` or `ConsentRoot` | `@c15t/svelte/styles.css`, and `@c15t/svelte/iab/styles.css` for IAB TCF |
113
+ | Astro | `styles` in the `c15t()` integration options | See [load Astro's stylesheets yourself](#load-astros-stylesheets-yourself) |
114
+
115
+ ```ts title="c15t.config.ts (Next.js)"
116
+ import { defineConsentConfig } from 'c15t/next';
117
+
118
+ export default defineConsentConfig({ options: { styles: false } });
119
+ ```
120
+
121
+ `styles: false` turns off only the stylesheets. Tokens from `ConsentTheme`
122
+ and slot classes still apply.
123
+
124
+ If you keep a `styles.css` import without `styles: false`, the surfaces still
125
+ look right, but the rules ship twice and the stylesheet link still holds back
126
+ the first paint. Remove the import, or add `styles: false` if you need it.
127
+
128
+ ## Where the dialog's rules come from
129
+
130
+ | Framework | The preference dialog's rules |
131
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
132
+ | Next.js, TanStack Start, React | In the dialog sheet that `ConsentDialog` and `ConsentWidget` render. It ships with the dialog's lazily loaded code. With `styles: false`, in `styles.css`. No `@c15t/react` or `@c15t/ui` module imports CSS, so a Next.js app that uses only the Pages Router builds without `transpilePackages` |
133
+ | Nuxt, Vue | The dialog component imports its stylesheet, so the rules load with the dialog's code, not the banner's |
134
+ | Astro | In `@c15t/ui/styles/sheets/dialog.css`. The Svelte dialog, the default `ui`, also needs the primitives stylesheet. c15t links both when a visitor first points at, focuses or opens a control that opens the dialog, waits for them before it shows the dialog, and keeps them across `ClientRouter` navigation. On a Tailwind CSS 3 site, the dialog's rules are in `c15t/astro/styles.css`, and c15t links only the primitives stylesheet |
135
+ | Svelte, SvelteKit | In the dialog's sheets, which load with the dialog's code. With `styles: false`, in `@c15t/svelte/styles.css` |
136
+ | HTML, JavaScript | Part of the stylesheet in the shadow root, which holds only the rules the stock surfaces use |
137
+
138
+ `styles.css` still holds every stock surface's rules for apps that set
139
+ `styles: false`. In that manual mode, IAB TCF also needs `iab/styles.css`
140
+ after the base stylesheet.
141
+
142
+ Earlier 3.0 alphas shipped the dialog's rules in `@c15t/ui/styles/dialog.css`,
143
+ which the dialog's code imported. That file, the `@c15t/ui/styles/dialog`
144
+ module and `c15t/astro/dialog.css` are now empty and stay only so existing
145
+ imports keep resolving. Remove those imports.
146
+
147
+ ## Order c15t's layer against your CSS
148
+
149
+ c15t puts its component rules in the cascade layer `components`. Tokens,
150
+ variables and keyframes stay unlayered. Each stylesheet, and each `<style>`
151
+ element the surfaces render, opens with Tailwind CSS 4's layer order:
152
+
153
+ ```css
154
+ @layer properties, theme, base, components, utilities;
155
+ ```
156
+
157
+ Cascade layers rank by the order they are first named, so `components` stays
158
+ above Tailwind's preflight in `base` and below `utilities`, whichever
159
+ stylesheet loads first. Without Tailwind the other layers stay empty. Vue's
160
+ per-component stylesheets open with the same statement.
161
+
162
+ What this means for your overrides:
163
+
164
+ * Any unlayered rule of yours outranks every c15t component rule, whatever its
165
+ specificity or load order. You do not need `!important`.
166
+ * A rule in one of your own layers wins only if that layer comes after
167
+ `components` in the layer order.
168
+ * Tokens are not layered. Set them as described in
169
+ [theme tokens](./tokens.md).
170
+
171
+ If your CSS declares its own layer order, load that statement before c15t's
172
+ rules. To put c15t's rules in a named layer, set `styles: false` and import
173
+ the stylesheet into that layer, such as
174
+ `@import 'c15t/react/styles.css' layer(c15t)`. Its component rules then sit
175
+ in `c15t.components`, so order `c15t` against your own layers.
176
+
177
+ ## Load Astro's stylesheets yourself
178
+
179
+ By default the Astro integration inlines the banner's rules into each page,
180
+ including the IAB banner rules when it sets `iab`, and links the dialog's
181
+ rules when a dialog opens. On a Tailwind CSS 3 site it adds
182
+ `c15t/astro/styles.css` and, with IAB, `c15t/astro/iab/styles.css` to every
183
+ page instead of inlining the banner's rules. To load the
184
+ files yourself, for example from a global stylesheet that names its own
185
+ layers, set `styles: false` in the `c15t()` options and import them after
186
+ your layer order statement. With `styles: false`, c15t inlines no rules and
187
+ links no stylesheet when the dialog opens. The Svelte dialog, the default
188
+ `ui`, needs the primitives stylesheet next to `styles.css`:
189
+
190
+ ```css title="src/styles/global.css"
191
+ @import 'c15t/astro/styles.css';
192
+ /* Only with ui: 'svelte'. */
193
+ @import 'c15t/astro/primitives.css';
194
+ /* Only when the integration sets iab. */
195
+ @import 'c15t/astro/iab/styles.css';
196
+ ```
197
+
198
+ Keep c15t's rules when you restyle the surfaces. The browser hides the Astro
199
+ banner with the `hidden` attribute, and c15t's rules make that attribute beat
200
+ the banner's own `display` rule.
201
+
202
+ ## Style the script tag's shadow root
203
+
204
+ The script tag and `init()` from `@c15t/browser` render into a shadow root with
205
+ their own copy of the stylesheet. Your page's CSS does not reach the UI, and
206
+ the UI's CSS does not reach your page. To style it:
207
+
208
+ | Option | What it does |
209
+ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
210
+ | `ui.theme` | Tokens, written after the stylesheet inside the shadow root |
211
+ | `ui.css` | A string of CSS added after the stylesheet and the theme |
212
+ | `ui.stylesheetURLs` | Stylesheets linked inside the shadow root, after c15t's, with the client's `nonce`. They load asynchronously, so the first frame can render without them |
213
+ | `::part()` | Page CSS that reaches a part by its slot key, as in `[data-c15t-ui]::part(consentBannerCard)` |
214
+ | `ui.shadow: false`, or `data-shadow="false"` | Renders into the page, so your stylesheets apply. c15t still injects its stylesheet next to the UI |
215
+ | `ui.styles: false` | Drops the injected stylesheet. With `shadow: false`, load `@c15t/browser/styles.css` from your bundle, or link `dist/c15t.css` from the same package version as the script |
216
+
217
+ A stylesheet in `ui.stylesheetURLs` should also load on the page. Some CSS,
218
+ such as Tailwind 4's `@property` rules, only takes effect in the page's
219
+ stylesheets. Of these options, the script tag has an attribute for `shadow`
220
+ only. Set the others with `c15t.push(['config', { ui: { ... } }])`.
221
+
222
+ ## Run without c15t's styles
223
+
224
+ `noStyle` removes c15t's stock classes from the markup, and in the script tag
225
+ also the injected stylesheet. Your part classes, `data-testid` and the `data-*`
226
+ attributes stay. [Component parts](./slots.md#remove-c15ts-classes-with-nostyle)
227
+ lists where each framework takes it.
228
+
229
+ `noStyle` does not supply layout, spacing, focus indicators or responsive
230
+ behavior. If a token seems to do nothing, check the layer order and your
231
+ selector before you reach for `noStyle`.
232
+
233
+ ## Check the result
234
+
235
+ 1. Open DevTools Network, clear site data and reload. No c15t stylesheet
236
+ request appears before the first paint. In the HTML or the Elements panel,
237
+ `<head>` holds c15t's rules: `<style data-href="c15t-first-paint">` in
238
+ React 19, or a `<style data-c15t-styles>` element in Svelte, SvelteKit
239
+ and Astro. In React 18, or with a `nonce`, the `<style>` sits next to the
240
+ banner instead.
241
+ 2. Open the preference dialog. It is styled on its first frame. Opening it
242
+ adds the dialog's rules: a second `<style>` element in React, Next.js,
243
+ TanStack Start, Svelte and SvelteKit, or a linked
244
+ `@c15t/ui/styles/sheets/dialog.css` in Astro.
245
+ 3. With `styles: false`, your imported `styles.css` loads once, and no c15t
246
+ `<style>` element appears.
247
+ 4. Select a banner part and read the Styles panel. c15t's rules appear under
248
+ `@layer components`, and your unlayered rules for the same property win.