@c15t/scripts 3.0.0-alpha.2 → 3.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/AGENTS.md +129 -63
  2. package/README.md +8 -29
  3. package/SKILL.md +33 -0
  4. package/dist/adobe-analytics.js +2 -0
  5. package/dist/ahrefs-analytics.js +2 -0
  6. package/dist/amplitude.js +2 -0
  7. package/dist/clearbit.js +2 -0
  8. package/dist/cloudflare-web-analytics.js +2 -0
  9. package/dist/cloudflare-zaraz.js +2 -0
  10. package/dist/crisp.js +2 -0
  11. package/dist/databuddy.js +2 -0
  12. package/dist/e2e-test-utils.js +2 -139
  13. package/dist/engine/compile.js +2 -89
  14. package/dist/engine/runtime.js +2 -448
  15. package/dist/events.js +2 -218
  16. package/dist/fathom-analytics.js +2 -0
  17. package/dist/front-chat.js +2 -0
  18. package/dist/google-tag-manager.js +2 -0
  19. package/dist/google-tag.js +2 -0
  20. package/dist/heap.js +2 -0
  21. package/dist/hightouch.js +2 -0
  22. package/dist/hotjar.js +2 -0
  23. package/dist/intercom.js +2 -0
  24. package/dist/klaviyo.js +2 -0
  25. package/dist/linkedin-insights.js +2 -0
  26. package/dist/logrocket.js +2 -0
  27. package/dist/matomo-analytics.js +2 -0
  28. package/dist/meta-pixel.js +2 -0
  29. package/dist/microsoft-clarity.js +2 -0
  30. package/dist/microsoft-uet.js +2 -0
  31. package/dist/mixpanel-analytics.js +2 -0
  32. package/dist/one-dollar-stats.js +2 -0
  33. package/dist/openai-pixel.js +2 -0
  34. package/dist/pinterest-tag.js +2 -0
  35. package/dist/pirsch.js +2 -0
  36. package/dist/plausible-analytics.js +2 -0
  37. package/dist/posthog.js +2 -0
  38. package/dist/promptwatch.js +2 -0
  39. package/dist/reddit-pixel.js +2 -0
  40. package/dist/registry.js +2 -422
  41. package/dist/resolve.js +2 -33
  42. package/dist/rudderstack.js +2 -0
  43. package/dist/rybbit-analytics.js +2 -0
  44. package/dist/segment.js +2 -0
  45. package/dist/snapchat-pixel.js +2 -0
  46. package/dist/tiktok-pixel.js +2 -0
  47. package/dist/types.js +2 -16
  48. package/dist/umami-analytics.js +2 -0
  49. package/dist/vendors/_shared/attributes.js +2 -14
  50. package/dist/vendors/_shared/google-consent.js +2 -27
  51. package/dist/vendors/_shared/install-builders.js +2 -21
  52. package/dist/vendors/_shared/required-id.js +2 -0
  53. package/dist/vendors/_shared/script-url.js +2 -28
  54. package/dist/vendors/ads-and-pixels/linkedin-insights.js +2 -48
  55. package/dist/vendors/ads-and-pixels/meta-pixel.js +2 -153
  56. package/dist/vendors/ads-and-pixels/microsoft-uet.js +2 -110
  57. package/dist/vendors/ads-and-pixels/openai-pixel.js +2 -88
  58. package/dist/vendors/ads-and-pixels/pinterest-tag.js +2 -123
  59. package/dist/vendors/ads-and-pixels/reddit-pixel.js +2 -107
  60. package/dist/vendors/ads-and-pixels/snapchat-pixel.js +2 -87
  61. package/dist/vendors/ads-and-pixels/tiktok-pixel.js +2 -89
  62. package/dist/vendors/ads-and-pixels/x-pixel.js +2 -48
  63. package/dist/vendors/analytics/adobe-analytics.js +2 -49
  64. package/dist/vendors/analytics/ahrefs-analytics.js +2 -27
  65. package/dist/vendors/analytics/amplitude.js +2 -134
  66. package/dist/vendors/analytics/clearbit.js +2 -28
  67. package/dist/vendors/analytics/cloudflare-web-analytics.js +2 -32
  68. package/dist/vendors/analytics/databuddy.js +2 -103
  69. package/dist/vendors/analytics/fathom-analytics.js +2 -35
  70. package/dist/vendors/analytics/google-tag.js +2 -78
  71. package/dist/vendors/analytics/heap.js +2 -134
  72. package/dist/vendors/analytics/hightouch.js +2 -109
  73. package/dist/vendors/analytics/hotjar.js +2 -44
  74. package/dist/vendors/analytics/logrocket.js +2 -58
  75. package/dist/vendors/analytics/matomo-analytics.js +2 -191
  76. package/dist/vendors/analytics/microsoft-clarity.js +2 -100
  77. package/dist/vendors/analytics/mixpanel-analytics.js +2 -93
  78. package/dist/vendors/analytics/one-dollar-stats.js +2 -30
  79. package/dist/vendors/analytics/pirsch.js +2 -67
  80. package/dist/vendors/analytics/plausible-analytics.js +2 -81
  81. package/dist/vendors/analytics/posthog.js +2 -200
  82. package/dist/vendors/analytics/promptwatch.js +2 -29
  83. package/dist/vendors/analytics/rudderstack.js +2 -183
  84. package/dist/vendors/analytics/rybbit-analytics.js +2 -63
  85. package/dist/vendors/analytics/segment.js +2 -65
  86. package/dist/vendors/analytics/umami-analytics.js +2 -39
  87. package/dist/vendors/analytics/vercel-analytics.js +2 -53
  88. package/dist/vendors/email-and-sms/klaviyo.js +2 -0
  89. package/dist/vendors/functional/crisp.js +2 -100
  90. package/dist/vendors/functional/front-chat.js +2 -64
  91. package/dist/vendors/functional/intercom.js +2 -45
  92. package/dist/vendors/tag-managers/cloudflare-zaraz.js +2 -98
  93. package/dist/vendors/tag-managers/google-tag-manager.js +2 -73
  94. package/dist/vercel-analytics.js +2 -0
  95. package/dist/x-pixel.js +2 -0
  96. package/dist-types/adobe-analytics.d.ts +2 -0
  97. package/dist-types/ahrefs-analytics.d.ts +2 -0
  98. package/dist-types/amplitude.d.ts +2 -0
  99. package/dist-types/clearbit.d.ts +2 -0
  100. package/dist-types/cloudflare-web-analytics.d.ts +2 -0
  101. package/dist-types/cloudflare-zaraz.d.ts +2 -0
  102. package/dist-types/crisp.d.ts +2 -0
  103. package/dist-types/databuddy.d.ts +2 -0
  104. package/dist-types/e2e-test-utils.d.ts +2 -0
  105. package/dist-types/engine/compile.d.ts +2 -3
  106. package/dist-types/engine/runtime.d.ts +2 -3
  107. package/dist-types/events.d.ts +2 -46
  108. package/dist-types/fathom-analytics.d.ts +2 -0
  109. package/dist-types/front-chat.d.ts +2 -0
  110. package/dist-types/google-tag-manager.d.ts +2 -0
  111. package/dist-types/google-tag.d.ts +2 -0
  112. package/dist-types/heap.d.ts +2 -0
  113. package/dist-types/hightouch.d.ts +2 -0
  114. package/dist-types/hotjar.d.ts +2 -0
  115. package/dist-types/intercom.d.ts +2 -0
  116. package/dist-types/klaviyo.d.ts +2 -0
  117. package/dist-types/linkedin-insights.d.ts +2 -0
  118. package/dist-types/logrocket.d.ts +2 -0
  119. package/dist-types/matomo-analytics.d.ts +2 -0
  120. package/dist-types/meta-pixel.d.ts +2 -0
  121. package/dist-types/microsoft-clarity.d.ts +2 -0
  122. package/dist-types/microsoft-uet.d.ts +2 -0
  123. package/dist-types/mixpanel-analytics.d.ts +2 -0
  124. package/dist-types/one-dollar-stats.d.ts +2 -0
  125. package/dist-types/openai-pixel.d.ts +2 -0
  126. package/dist-types/pinterest-tag.d.ts +2 -0
  127. package/dist-types/pirsch.d.ts +2 -0
  128. package/dist-types/plausible-analytics.d.ts +2 -0
  129. package/dist-types/posthog.d.ts +2 -0
  130. package/dist-types/promptwatch.d.ts +2 -0
  131. package/dist-types/reddit-pixel.d.ts +2 -0
  132. package/dist-types/registry.d.ts +2 -485
  133. package/dist-types/resolve.d.ts +2 -9
  134. package/dist-types/rudderstack.d.ts +2 -0
  135. package/dist-types/rybbit-analytics.d.ts +2 -0
  136. package/dist-types/segment.d.ts +2 -0
  137. package/dist-types/snapchat-pixel.d.ts +2 -0
  138. package/dist-types/tiktok-pixel.d.ts +2 -0
  139. package/dist-types/types.d.ts +2 -314
  140. package/dist-types/umami-analytics.d.ts +2 -0
  141. package/dist-types/vendors/_shared/attributes.d.ts +2 -35
  142. package/dist-types/vendors/_shared/google-consent.d.ts +2 -47
  143. package/dist-types/vendors/_shared/install-builders.d.ts +2 -30
  144. package/dist-types/vendors/_shared/required-id.d.ts +2 -0
  145. package/dist-types/vendors/_shared/script-url.d.ts +2 -75
  146. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +2 -92
  147. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +2 -289
  148. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +2 -105
  149. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +2 -211
  150. package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +2 -295
  151. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +2 -210
  152. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +2 -171
  153. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +2 -106
  154. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +2 -183
  155. package/dist-types/vendors/analytics/adobe-analytics.d.ts +2 -75
  156. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +2 -62
  157. package/dist-types/vendors/analytics/amplitude.d.ts +2 -234
  158. package/dist-types/vendors/analytics/clearbit.d.ts +2 -60
  159. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +2 -67
  160. package/dist-types/vendors/analytics/databuddy.d.ts +2 -147
  161. package/dist-types/vendors/analytics/fathom-analytics.d.ts +2 -90
  162. package/dist-types/vendors/analytics/google-tag.d.ts +2 -95
  163. package/dist-types/vendors/analytics/heap.d.ts +2 -316
  164. package/dist-types/vendors/analytics/hightouch.d.ts +2 -285
  165. package/dist-types/vendors/analytics/hotjar.d.ts +2 -73
  166. package/dist-types/vendors/analytics/logrocket.d.ts +2 -101
  167. package/dist-types/vendors/analytics/matomo-analytics.d.ts +2 -41
  168. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +2 -97
  169. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +2 -113
  170. package/dist-types/vendors/analytics/one-dollar-stats.d.ts +2 -39
  171. package/dist-types/vendors/analytics/pirsch.d.ts +2 -96
  172. package/dist-types/vendors/analytics/plausible-analytics.d.ts +2 -122
  173. package/dist-types/vendors/analytics/posthog.d.ts +2 -175
  174. package/dist-types/vendors/analytics/promptwatch.d.ts +2 -36
  175. package/dist-types/vendors/analytics/rudderstack.d.ts +2 -330
  176. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +2 -82
  177. package/dist-types/vendors/analytics/segment.d.ts +2 -164
  178. package/dist-types/vendors/analytics/umami-analytics.d.ts +2 -93
  179. package/dist-types/vendors/analytics/vercel-analytics.d.ts +2 -66
  180. package/dist-types/vendors/email-and-sms/klaviyo.d.ts +2 -0
  181. package/dist-types/vendors/functional/crisp.d.ts +2 -78
  182. package/dist-types/vendors/functional/front-chat.d.ts +2 -62
  183. package/dist-types/vendors/functional/intercom.d.ts +2 -135
  184. package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +2 -39
  185. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +2 -96
  186. package/dist-types/vercel-analytics.d.ts +2 -0
  187. package/dist-types/x-pixel.d.ts +2 -0
  188. package/docs/README.md +129 -63
  189. package/docs/assets/v3/bottom-bar.png +0 -0
  190. package/docs/assets/v3/brand-card.png +0 -0
  191. package/docs/assets/v3/brand-preferences.png +0 -0
  192. package/docs/assets/v3/choice-wall.png +0 -0
  193. package/docs/assets/v3/headless-bar-html.png +0 -0
  194. package/docs/assets/v3/headless-bar-mobile.png +0 -0
  195. package/docs/assets/v3/headless-bar.png +0 -0
  196. package/docs/assets/v3/slim-bar.png +0 -0
  197. package/docs/concepts/choose-your-setup.md +87 -0
  198. package/docs/concepts/consent-categories.md +84 -0
  199. package/docs/{guides → concepts}/consent-state.md +89 -105
  200. package/docs/{guides → concepts}/data-fetching.md +31 -27
  201. package/docs/concepts/how-consent-works.md +123 -0
  202. package/docs/concepts/policies.md +71 -0
  203. package/docs/customization/class-names.md +202 -0
  204. package/docs/customization/dark-mode.md +157 -0
  205. package/docs/customization/motion.md +119 -0
  206. package/docs/customization/overview.md +67 -34
  207. package/docs/customization/recipes.md +839 -49
  208. package/docs/customization/slots.md +216 -35
  209. package/docs/customization/stylesheets.md +147 -0
  210. package/docs/customization/tailwind.md +842 -0
  211. package/docs/customization/tokens.md +163 -96
  212. package/docs/customization/translations.md +60 -3
  213. package/docs/frameworks/astro/embeds.md +160 -0
  214. package/docs/frameworks/astro/network-blocker.md +86 -0
  215. package/docs/frameworks/astro/scripts.md +155 -0
  216. package/docs/frameworks/html/embeds.md +142 -0
  217. package/docs/frameworks/html/network-blocker.md +105 -0
  218. package/docs/frameworks/html/scripts.md +164 -0
  219. package/docs/frameworks/javascript/scripts.md +137 -0
  220. package/docs/frameworks/next/embeds.md +90 -0
  221. package/docs/frameworks/next/network-blocker.md +153 -0
  222. package/docs/frameworks/next/scripts.md +196 -0
  223. package/docs/frameworks/nuxt/embeds.md +81 -0
  224. package/docs/frameworks/nuxt/network-blocker.md +97 -0
  225. package/docs/frameworks/nuxt/scripts.md +89 -0
  226. package/docs/frameworks/react/embeds.md +89 -0
  227. package/docs/frameworks/react/network-blocker.md +140 -0
  228. package/docs/frameworks/react/scripts.md +115 -0
  229. package/docs/frameworks/svelte/embeds.md +96 -0
  230. package/docs/frameworks/svelte/network-blocker.md +141 -0
  231. package/docs/frameworks/svelte/scripts.md +144 -0
  232. package/docs/frameworks/sveltekit/embeds.md +103 -0
  233. package/docs/frameworks/sveltekit/network-blocker.md +159 -0
  234. package/docs/frameworks/sveltekit/scripts.md +172 -0
  235. package/docs/frameworks/tanstack-start/embeds.md +96 -0
  236. package/docs/frameworks/tanstack-start/network-blocker.md +145 -0
  237. package/docs/frameworks/tanstack-start/scripts.md +103 -0
  238. package/docs/frameworks/vue/embeds.md +84 -0
  239. package/docs/frameworks/vue/network-blocker.md +99 -0
  240. package/docs/frameworks/vue/scripts.md +93 -0
  241. package/docs/guides/banner-experiments.md +654 -0
  242. package/docs/guides/troubleshooting.md +120 -47
  243. package/docs/guides/verify-consent.md +81 -49
  244. package/docs/integrations/adobe-analytics.md +167 -159
  245. package/docs/integrations/ahrefs-analytics.md +152 -154
  246. package/docs/integrations/amplitude.md +162 -156
  247. package/docs/integrations/building-integrations.md +136 -37
  248. package/docs/integrations/clearbit.md +154 -154
  249. package/docs/integrations/cloudflare-web-analytics.md +156 -156
  250. package/docs/integrations/cloudflare-zaraz.md +209 -261
  251. package/docs/integrations/crisp.md +164 -158
  252. package/docs/integrations/databuddy.md +157 -173
  253. package/docs/integrations/fathom-analytics.md +158 -156
  254. package/docs/integrations/front-chat.md +167 -167
  255. package/docs/integrations/google-maps.md +118 -83
  256. package/docs/integrations/google-tag-manager.md +178 -163
  257. package/docs/integrations/google-tag.md +163 -160
  258. package/docs/integrations/heap.md +163 -155
  259. package/docs/integrations/hightouch.md +161 -157
  260. package/docs/integrations/hotjar.md +159 -155
  261. package/docs/integrations/intercom.md +183 -153
  262. package/docs/integrations/klaviyo.md +486 -0
  263. package/docs/integrations/linkedin-insights.md +174 -150
  264. package/docs/integrations/logrocket.md +160 -156
  265. package/docs/integrations/matomo-analytics.md +188 -178
  266. package/docs/integrations/meta-pixel.md +188 -150
  267. package/docs/integrations/microsoft-clarity.md +163 -155
  268. package/docs/integrations/microsoft-uet.md +148 -154
  269. package/docs/integrations/mixpanel-analytics.md +155 -160
  270. package/docs/integrations/one-dollar-stats.md +166 -165
  271. package/docs/integrations/openai-pixel.md +204 -301
  272. package/docs/integrations/overview.md +137 -80
  273. package/docs/integrations/pinterest-tag.md +191 -183
  274. package/docs/integrations/pirsch.md +169 -159
  275. package/docs/integrations/plausible-analytics.md +172 -158
  276. package/docs/integrations/posthog.md +313 -240
  277. package/docs/integrations/promptwatch.md +154 -154
  278. package/docs/integrations/reddit-pixel.md +185 -157
  279. package/docs/integrations/rudderstack.md +201 -186
  280. package/docs/integrations/rybbit-analytics.md +171 -160
  281. package/docs/integrations/segment.md +182 -154
  282. package/docs/integrations/snapchat-pixel.md +186 -156
  283. package/docs/integrations/tiktok-pixel.md +171 -150
  284. package/docs/integrations/umami-analytics.md +163 -158
  285. package/docs/integrations/vercel-analytics.md +166 -157
  286. package/docs/integrations/x-pixel.md +176 -150
  287. package/docs/integrations/youtube.md +121 -86
  288. package/docs/upgrade-v3.md +496 -467
  289. package/package.json +10 -257
  290. package/dist-types/__tests__/helpers.d.ts +0 -141
  291. package/docs/assets/v3/brand-bar.png +0 -0
  292. package/docs/assets/v3/mobile-card.png +0 -0
  293. package/docs/assets/v3/preferences.png +0 -0
  294. package/docs/frameworks/javascript/script-loader.md +0 -100
  295. package/docs/frameworks/next/script-loader.md +0 -216
  296. package/docs/frameworks/react/script-loader.md +0 -69
  297. package/docs/guides/deployment-modes.md +0 -75
  298. package/docs/guides/shared-consent-controls.md +0 -158
  299. package/docs/integrations/clear-on-revocation.md +0 -167
  300. package/docs/integrations/granular-consent.md +0 -210
@@ -1,55 +1,236 @@
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` 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 `ConsentManagerProvider` | `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
+ Only React renders the toolbar. Vue has no toolbar, and the toolbar slots only
133
+ reach Astro's React dialog.
134
+
135
+ ## Legal links and IAB TCF parts
136
+
137
+ | Component | `components` keys | `theme.slots` keys |
138
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
139
+ | Legal links | `legal-links.root`, and `link.banner`, `link.dialog`, `link.manager` for one link | None |
140
+ | IAB banner | `iab-banner.root`, `cardShell`, `card`, `header`, `title`, `description`, `partnersLink`, `purposeList`, `purposeMore`, `legitimateInterestNotice`, `footer`, `actions`, `actionGroup`, `overlay` | `iabConsentBanner`, `iabConsentBannerCard`, `iabConsentBannerHeader`, `iabConsentBannerFooter`, `iabConsentBannerTag`, `iabConsentBannerOverlay` |
141
+ | 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` |
142
+ | IAB purpose, stack and vendor rows | `iab-purpose-item.*`, `iab-stack-item.*`, `iab-vendor-list.*` | None |
143
+
144
+ Legal links take no `theme.slots` key. They keep their stock link class, and
145
+ a description slot's classes stay on the description around them.
146
+
147
+ ## ConsentGate placeholder parts
148
+
149
+ `ConsentGate` shows a placeholder card while its category is denied. React,
150
+ Next.js, TanStack Start, Vue, Nuxt, Svelte and SvelteKit render the same
151
+ three parts:
152
+
153
+ | Part | `components` key | `theme.slots` key | `data-testid` |
154
+ | ----------------------------- | --------------------- | ------------------- | -------------------------- |
155
+ | Placeholder card | `consent-gate.root` | `consentGate` | `consent-gate-placeholder` |
156
+ | Title | `consent-gate.title` | `consentGateTitle` | `consent-gate-title` |
157
+ | Button that opens preferences | `consent-gate.button` | `consentGateButton` | `consent-gate-button` |
158
+
159
+ The button part applies on top of `button.primary`, or `buttonPrimary`. The
160
+ parts only reach the built-in placeholder. A placeholder you pass yourself
161
+ takes your own classes, and the wrapper around the gate takes `className` in
162
+ React or `class` in Svelte. Astro, HTML and JavaScript have no `ConsentGate`.
163
+
164
+ ## Style parts from outside the script tag's shadow root
165
+
166
+ The script tag and `init()` render into a shadow root. Every part that has a
167
+ `theme.slots` key carries it in a `part` attribute, so page CSS can reach it
168
+ with `::part()`:
169
+
170
+ ```css
171
+ [data-c15t-ui]::part(consentBannerCard) {
172
+ border: 3px solid #6943a3;
19
173
  }
20
174
  ```
21
175
 
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.
176
+ ## Select on state attributes
177
+
178
+ Parts carry `data-*` attributes that describe their state. Select on these
179
+ instead of guessing at markup:
180
+
181
+ | Element | Attributes |
182
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
183
+ | Banner root | `data-prompt`, `data-model`, `data-variant`, `data-position`, `data-blocking` |
184
+ | Action buttons | `data-action` (`accept`, `reject`, `customize`, `dismiss` or `save`), `data-variant`, `data-mode` |
185
+ | Footer and action groups | `data-direction`, `data-fill`, `data-split` |
186
+ | Right links | `data-action="right"`, `data-right` |
187
+ | Preference dialog | `data-state` (`open` or `closed`), on the elements listed in [motion](./motion.md#animate-your-own-rules-on-dialog-state) |
188
+ | Category switch | `data-state`, `data-disabled` |
189
+
190
+ The script tag's banner root has `data-variant`, `data-position` and
191
+ `data-blocking` only, with `data-blocking` set to `"true"` or `"false"`. Its
192
+ right links carry `data-action="customize"`.
193
+
194
+ The banner card does not inherit the root's attributes. With Tailwind, give
195
+ the root `group` and read the root's attribute from a child part:
196
+
197
+ ```tsx
198
+ components: {
199
+ banner: {
200
+ root: { className: 'group' },
201
+ card: { className: 'group-data-[variant=bar]:rounded-none' },
202
+ },
203
+ },
204
+ ```
25
205
 
26
- ## Read attributes on the right element
206
+ Test notices as well as choice prompts. A notice has an acknowledge action,
207
+ `data-action="dismiss"`, instead of accept and reject.
27
208
 
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.
209
+ ## Do not target c15t's class names
32
210
 
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 |
211
+ c15t's stock class names are generated from CSS Modules and end in a hash, such
212
+ as `c15t-ui-card-lgjVq`. The hash changes whenever the source CSS changes, and
213
+ the classes disappear under `noStyle`. A rule that targets one breaks on an
214
+ upgrade without warning. Target a part API, `data-testid`, a `data-*`
215
+ attribute or `::part()` instead.
42
216
 
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.
217
+ ## Remove c15t's classes with noStyle
45
218
 
46
- ## When to remove styles
219
+ `noStyle` renders the same markup and behavior without c15t's stock classes. It
220
+ keeps your part classes and styles, `data-testid` and the `data-*` attributes.
221
+ It does not replace layout, spacing, focus indicators or responsive behavior,
222
+ so use it when you intend to write all of that yourself.
47
223
 
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.
224
+ | Framework | Where |
225
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
226
+ | 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 |
227
+ | Svelte, SvelteKit | `noStyle` in the provider options, or the prop on a stock component |
228
+ | Astro | `noStyle` prop on `ConsentBanner` and `IABConsentBanner` |
229
+ | HTML, JavaScript | `ui.noStyle`, which also drops the bundled stylesheet |
230
+ | 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
231
 
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.
232
+ In `theme.slots`, `{ noStyle: true }` on one slot replaces that part's stock
233
+ classes in Svelte, Astro's banner and the script tag. React and Vue, including
234
+ Astro's React and Vue dialog islands, ignore a slot's `noStyle`, so its classes
235
+ apply on top of the stock ones. If the markup itself must change, use your framework's compound
236
+ components or headless API.
@@ -0,0 +1,147 @@
1
+ ---
2
+ title: Stylesheets and CSS layers
3
+ description: Load the right c15t stylesheet for your framework, see when the
4
+ dialog's CSS loads, order c15t's cascade layer against your own, and run c15t
5
+ without its styles.
6
+ group: customization
7
+ ---
8
+
9
+ ## Load one stylesheet for your framework
10
+
11
+ | Framework | What to load | Where |
12
+ | ----------------- | -------------------------------- | -------------------------------------------------------------------- |
13
+ | Next.js | `c15t/next/styles.css` | Your global stylesheet, or the layout that renders the consent root |
14
+ | TanStack Start | `c15t/tanstack-start/styles.css` | A `<link>` from the root route's `head()`, or your global stylesheet |
15
+ | React | `c15t/react/styles.css` | The module that renders `ConsentProvider`, or your global stylesheet |
16
+ | Nuxt, Vue | Nothing | Each Vue component imports its own stylesheet |
17
+ | Astro | Nothing | The integration adds `c15t/astro/styles.css` to every page |
18
+ | Svelte, SvelteKit | `@c15t/svelte/styles.css` | Your entry module or root layout |
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
+ Load it once. With IAB TCF in Next.js, TanStack Start, React, Svelte or
23
+ SvelteKit, also load the adapter's `iab/styles.css`, such as
24
+ `c15t/next/iab/styles.css`, after `styles.css`. Astro adds its IAB stylesheet
25
+ when the integration sets `iab`. Tailwind 3 uses the same files and adds a
26
+ PostCSS plugin; [Tailwind CSS](./tailwind.md#set-up-tailwind-css-3)
27
+ shows the setup.
28
+
29
+ ## What loads with the first paint
30
+
31
+ A stylesheet that blocks rendering should hold only what the first paint can
32
+ show. c15t's main stylesheet holds the default tokens, every c15t CSS variable,
33
+ and the rules for the banner, the floating trigger and the `ConsentGate`
34
+ placeholder. The preference dialog's rules load separately in most frameworks:
35
+
36
+ | Framework | The preference dialog's rules |
37
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
38
+ | Next.js, TanStack Start, React | The dialog's code imports `@c15t/ui/styles/dialog.css`. Your bundler emits it with the dialog's lazy chunk and loads it before that chunk runs, so the dialog never renders unstyled |
39
+ | Nuxt, Vue | The dialog component imports its stylesheet, so the rules load with the dialog's code, not the banner's |
40
+ | Astro | c15t links the dialog's stylesheets when a visitor first points at, focuses or opens a control that opens the dialog, and keeps them across `ClientRouter` navigation |
41
+ | Svelte, SvelteKit | Part of `@c15t/svelte/styles.css`, so they load up front |
42
+ | HTML, JavaScript | Part of the stylesheet in the shadow root, which holds only the rules the stock surfaces use |
43
+
44
+ In React, Next.js and TanStack Start, do not import `dialog.css` yourself. The
45
+ `@c15t/react/components/consent-dialog`, `/components/consent-widget`,
46
+ `/primitives`, `/primitives/*` and `/iab` entry points import it as soon as
47
+ you import them, because they render dialog parts outside the lazy chunk.
48
+
49
+ These modules import the stylesheet through `@c15t/ui/styles/dialog`. Under
50
+ the `node` export condition that module imports nothing, so server code that
51
+ loads `@c15t/react` with plain Node, such as the Pages Router or an SSR build
52
+ that keeps dependencies external, does not fail on the `.css` file. In your own
53
+ components, import `@c15t/ui/styles/dialog` rather than the `.css` file if the
54
+ module can run on the server.
55
+
56
+ ## Order c15t's layer against your CSS
57
+
58
+ c15t puts its component rules in the cascade layer `components`. Tokens,
59
+ variables and keyframes stay unlayered. Each stylesheet opens with Tailwind
60
+ CSS 4's layer order:
61
+
62
+ ```css
63
+ @layer properties, theme, base, components, utilities;
64
+ ```
65
+
66
+ Cascade layers rank by the order they are first named, so `components` stays
67
+ above Tailwind's preflight in `base` and below `utilities`, whichever
68
+ stylesheet loads first. Without Tailwind the other layers stay empty. Vue's
69
+ per-component stylesheets open with the same statement.
70
+
71
+ What this means for your overrides:
72
+
73
+ * Any unlayered rule of yours outranks every c15t component rule, whatever its
74
+ specificity or load order. You do not need `!important`.
75
+ * A rule in one of your own layers wins only if that layer comes after
76
+ `components` in the layer order.
77
+ * Tokens are not layered. Set them as described in
78
+ [theme tokens](./tokens.md).
79
+
80
+ If your CSS declares its own layer order, load that statement before c15t's
81
+ stylesheet. If you import c15t's stylesheet into a named layer, such as
82
+ `@import 'c15t/react/styles.css' layer(c15t)`, the dialog's lazy rules still
83
+ join the top-level `components` layer. List `components` in your statement,
84
+ for example `@layer c15t, components, app;`, so it does not land after your
85
+ own layers.
86
+
87
+ ## Load Astro's stylesheets yourself
88
+
89
+ The Astro integration adds `c15t/astro/styles.css` to every page ahead of your
90
+ own CSS. To control the order yourself, for example from a global stylesheet
91
+ that names its own layers, set `styles: false` in the `c15t()` options and
92
+ import the files after your layer order statement. With `styles: false`, c15t
93
+ links no dialog stylesheet either, so import the dialog's rules too. The
94
+ Svelte dialog, the default `ui`, also needs the primitives stylesheet:
95
+
96
+ ```css title="src/styles/global.css"
97
+ @import 'c15t/astro/styles.css';
98
+ @import 'c15t/astro/dialog.css';
99
+ /* Only with ui: 'svelte'. */
100
+ @import 'c15t/astro/primitives.css';
101
+ /* Only when the integration sets iab. */
102
+ @import 'c15t/astro/iab/styles.css';
103
+ ```
104
+
105
+ Keep c15t's stylesheet when you restyle the surfaces. The browser hides the
106
+ Astro banner with the `hidden` attribute, and the stylesheet makes that
107
+ attribute beat the banner's own `display` rule.
108
+
109
+ ## Style the script tag's shadow root
110
+
111
+ The script tag and `init()` from `@c15t/browser` render into a shadow root with
112
+ their own copy of the stylesheet. Your page's CSS does not reach the UI, and
113
+ the UI's CSS does not reach your page. To style it:
114
+
115
+ | Option | What it does |
116
+ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
117
+ | `ui.theme` | Tokens, written after the stylesheet inside the shadow root |
118
+ | `ui.css` | A string of CSS added after the stylesheet and the theme |
119
+ | `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 |
120
+ | `::part()` | Page CSS that reaches a part by its slot key, as in `[data-c15t-ui]::part(consentBannerCard)` |
121
+ | `ui.shadow: false`, or `data-shadow="false"` | Renders into the page, so your stylesheets apply. c15t still injects its stylesheet next to the UI |
122
+ | `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 |
123
+
124
+ A stylesheet in `ui.stylesheetURLs` should also load on the page. Some CSS,
125
+ such as Tailwind 4's `@property` rules, only takes effect in the page's
126
+ stylesheets. Of these options, the script tag has an attribute for `shadow`
127
+ only. Set the others with `c15t.push(['config', { ui: { ... } }])`.
128
+
129
+ ## Run without c15t's styles
130
+
131
+ `noStyle` removes c15t's stock classes from the markup, and in the script tag
132
+ also the injected stylesheet. Your part classes, `data-testid` and the `data-*`
133
+ attributes stay. [Component parts](./slots.md#remove-c15ts-classes-with-nostyle)
134
+ lists where each framework takes it.
135
+
136
+ `noStyle` does not supply layout, spacing, focus indicators or responsive
137
+ behavior. If a token seems to do nothing, check the layer order and your
138
+ selector before you reach for `noStyle`.
139
+
140
+ ## Check the result
141
+
142
+ 1. Open DevTools Network, clear site data and reload. Your framework's c15t
143
+ stylesheet loads once, and no second copy appears.
144
+ 2. Open the preference dialog. It is styled on its first frame, with no flash
145
+ of unstyled content.
146
+ 3. Select a banner part and read the Styles panel. c15t's rules appear under
147
+ `@layer components`, and your unlayered rules for the same property win.