@c15t/nextjs 2.2.1 → 3.0.0-alpha.1

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 (221) hide show
  1. package/AGENTS.md +103 -142
  2. package/README.md +4 -4
  3. package/dist/api.js +1 -0
  4. package/dist/config.js +1 -0
  5. package/dist/devtools.js +2 -0
  6. package/dist/headers.js +1 -0
  7. package/dist/iab/styles.css +1 -1
  8. package/dist/iab/styles.tw3.css +27 -19
  9. package/dist/index.js +1 -1
  10. package/dist/middleware.js +1 -0
  11. package/dist/node-bridge.js +1 -0
  12. package/dist/pages.js +1 -0
  13. package/dist/proxy.js +1 -0
  14. package/dist/root.js +2 -0
  15. package/dist/server.js +1 -0
  16. package/dist/static.js +1 -0
  17. package/dist/styles.css +1 -1
  18. package/dist/styles.tw3.css +67 -29
  19. package/dist/version.js +1 -1
  20. package/dist-types/api.d.ts +88 -0
  21. package/dist-types/config.d.ts +110 -0
  22. package/dist-types/devtools.d.ts +1 -0
  23. package/dist-types/headers.d.ts +4 -0
  24. package/dist-types/index.d.ts +28 -10
  25. package/dist-types/middleware.d.ts +15 -0
  26. package/dist-types/node-bridge.d.ts +57 -0
  27. package/dist-types/pages.d.ts +88 -0
  28. package/dist-types/proxy.d.ts +34 -0
  29. package/dist-types/root.d.ts +92 -0
  30. package/dist-types/server.d.ts +164 -0
  31. package/dist-types/static.d.ts +42 -0
  32. package/dist-types/types.d.ts +5 -36
  33. package/dist-types/version.d.ts +1 -1
  34. package/docs/README.md +103 -142
  35. package/docs/assets/v3/brand-bar.png +0 -0
  36. package/docs/assets/v3/brand-card.png +0 -0
  37. package/docs/assets/v3/choice-wall.png +0 -0
  38. package/docs/assets/v3/mobile-card.png +0 -0
  39. package/docs/assets/v3/preferences.png +0 -0
  40. package/docs/customization/overview.md +45 -0
  41. package/docs/customization/recipes.md +79 -0
  42. package/docs/customization/slots.md +55 -0
  43. package/docs/customization/tokens.md +76 -0
  44. package/docs/customization/translations.md +49 -0
  45. package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
  46. package/docs/frameworks/next/app-router.md +403 -0
  47. package/docs/frameworks/next/client-side.md +118 -0
  48. package/docs/frameworks/next/components/consent-banner.md +251 -211
  49. package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
  50. package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
  51. package/docs/frameworks/next/components/consent-dialog.md +189 -134
  52. package/docs/frameworks/next/components/consent-manager-provider.md +68 -318
  53. package/docs/frameworks/next/components/consent-widget.md +172 -114
  54. package/docs/frameworks/next/components/dev-tools.md +199 -40
  55. package/docs/frameworks/next/components/frame.md +137 -42
  56. package/docs/frameworks/next/concepts/consent-categories.md +24 -89
  57. package/docs/frameworks/next/concepts/policy-presets.md +142 -0
  58. package/docs/frameworks/next/content-security-policy.md +189 -0
  59. package/docs/frameworks/next/data-fetching.md +74 -0
  60. package/docs/frameworks/next/geography-headers.md +251 -0
  61. package/docs/frameworks/next/headless.md +95 -185
  62. package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
  63. package/docs/frameworks/next/iab/overview.md +37 -107
  64. package/docs/frameworks/next/optimization.md +158 -194
  65. package/docs/frameworks/next/pages-router.md +296 -0
  66. package/docs/frameworks/next/quickstart.md +31 -132
  67. package/docs/frameworks/next/script-loader.md +140 -465
  68. package/docs/frameworks/next/server-side.md +97 -130
  69. package/docs/frameworks/next/static-export.md +164 -0
  70. package/docs/frameworks/next/styling/overview.md +174 -248
  71. package/docs/frameworks/next/troubleshooting.md +134 -144
  72. package/docs/guides/consent-state.md +60 -0
  73. package/docs/guides/data-fetching.md +163 -0
  74. package/docs/guides/deployment-modes.md +63 -0
  75. package/docs/guides/troubleshooting.md +68 -0
  76. package/docs/guides/verify-consent.md +62 -0
  77. package/docs/integrations/adobe-analytics.md +239 -105
  78. package/docs/integrations/ahrefs-analytics.md +238 -104
  79. package/docs/integrations/amplitude.md +219 -157
  80. package/docs/integrations/building-integrations.md +32 -224
  81. package/docs/integrations/clear-on-revocation.md +167 -0
  82. package/docs/integrations/clearbit.md +247 -86
  83. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  84. package/docs/integrations/crisp.md +251 -97
  85. package/docs/integrations/databuddy.md +259 -153
  86. package/docs/integrations/fathom-analytics.md +239 -96
  87. package/docs/integrations/google-maps.md +328 -207
  88. package/docs/integrations/google-tag-manager.md +248 -96
  89. package/docs/integrations/google-tag.md +261 -90
  90. package/docs/integrations/heap.md +222 -149
  91. package/docs/integrations/hightouch.md +225 -131
  92. package/docs/integrations/hotjar.md +239 -90
  93. package/docs/integrations/intercom.md +239 -98
  94. package/docs/integrations/linkedin-insights.md +243 -113
  95. package/docs/integrations/logrocket.md +241 -123
  96. package/docs/integrations/matomo-analytics.md +256 -111
  97. package/docs/integrations/meta-pixel.md +197 -324
  98. package/docs/integrations/microsoft-clarity.md +233 -114
  99. package/docs/integrations/microsoft-uet.md +245 -110
  100. package/docs/integrations/mixpanel-analytics.md +252 -87
  101. package/docs/integrations/openai-pixel.md +441 -0
  102. package/docs/integrations/overview.md +95 -133
  103. package/docs/integrations/pirsch.md +249 -96
  104. package/docs/integrations/plausible-analytics.md +241 -100
  105. package/docs/integrations/posthog.md +353 -214
  106. package/docs/integrations/promptwatch.md +251 -81
  107. package/docs/integrations/reddit-pixel.md +226 -173
  108. package/docs/integrations/rudderstack.md +244 -187
  109. package/docs/integrations/rybbit-analytics.md +244 -91
  110. package/docs/integrations/segment.md +238 -92
  111. package/docs/integrations/snapchat-pixel.md +240 -110
  112. package/docs/integrations/tiktok-pixel.md +249 -81
  113. package/docs/integrations/umami-analytics.md +242 -95
  114. package/docs/integrations/vercel-analytics.md +242 -90
  115. package/docs/integrations/x-pixel.md +238 -104
  116. package/docs/integrations/youtube.md +354 -142
  117. package/docs/upgrade-v3.md +334 -0
  118. package/iab/styles.css +1 -1
  119. package/iab/styles.tw3.css +1 -1
  120. package/package.json +106 -65
  121. package/readme.json +3 -3
  122. package/src/iab/styles.css +1 -1
  123. package/src/iab/styles.tw3.css +1 -1
  124. package/src/styles.css +1 -1
  125. package/src/styles.tw3.css +1 -1
  126. package/styles.css +1 -1
  127. package/styles.tw3.css +1 -1
  128. package/client/components/consent-dialog-link.js +0 -3
  129. package/client/components/integrations.js +0 -3
  130. package/dist/components/integrations/index.cjs +0 -1
  131. package/dist/components/integrations/index.js +0 -1
  132. package/dist/headless.cjs +0 -1
  133. package/dist/index.cjs +0 -1
  134. package/dist/libs/browser-initial-data.cjs +0 -1
  135. package/dist/libs/browser-initial-data.js +0 -1
  136. package/dist/libs/initial-data.cjs +0 -1
  137. package/dist/libs/initial-data.js +0 -1
  138. package/dist/types.cjs +0 -1
  139. package/dist/version.cjs +0 -1
  140. package/dist-types/components/integrations/index.d.ts +0 -1
  141. package/dist-types/libs/browser-initial-data.d.ts +0 -9
  142. package/dist-types/libs/initial-data.d.ts +0 -33
  143. package/docs/frameworks/next/building-headless-components.md +0 -379
  144. package/docs/frameworks/next/callbacks.md +0 -186
  145. package/docs/frameworks/next/concepts/client-modes.md +0 -177
  146. package/docs/frameworks/next/concepts/consent-models.md +0 -117
  147. package/docs/frameworks/next/concepts/cookie-management.md +0 -122
  148. package/docs/frameworks/next/concepts/glossary.md +0 -24
  149. package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
  150. package/docs/frameworks/next/concepts/policy-packs.md +0 -230
  151. package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
  152. package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
  153. package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
  154. package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
  155. package/docs/frameworks/next/hooks/use-draggable.md +0 -59
  156. package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
  157. package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
  158. package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
  159. package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
  160. package/docs/frameworks/next/hooks/use-translations.md +0 -55
  161. package/docs/frameworks/next/iab/consent-banner.md +0 -91
  162. package/docs/frameworks/next/iab/consent-dialog.md +0 -129
  163. package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
  164. package/docs/frameworks/next/iframe-blocking.md +0 -106
  165. package/docs/frameworks/next/internationalization.md +0 -207
  166. package/docs/frameworks/next/network-blocker.md +0 -140
  167. package/docs/frameworks/next/policy-packs.md +0 -248
  168. package/docs/frameworks/next/styling/classnames.md +0 -94
  169. package/docs/frameworks/next/styling/color-scheme.md +0 -84
  170. package/docs/frameworks/next/styling/css-variables.md +0 -53
  171. package/docs/frameworks/next/styling/slots.md +0 -94
  172. package/docs/frameworks/next/styling/tailwind.md +0 -137
  173. package/docs/frameworks/next/styling/tokens.md +0 -156
  174. package/docs/shared/concepts/client-modes.md +0 -103
  175. package/docs/shared/concepts/consent-categories.md +0 -41
  176. package/docs/shared/concepts/consent-models.md +0 -72
  177. package/docs/shared/concepts/cookie-management.md +0 -88
  178. package/docs/shared/concepts/glossary.md +0 -24
  179. package/docs/shared/concepts/initialization-flow.md +0 -105
  180. package/docs/shared/concepts/policy-packs.md +0 -225
  181. package/docs/shared/react/components/consent-banner.md +0 -242
  182. package/docs/shared/react/components/consent-dialog-link.md +0 -45
  183. package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
  184. package/docs/shared/react/components/consent-dialog.md +0 -119
  185. package/docs/shared/react/components/consent-manager-provider.md +0 -225
  186. package/docs/shared/react/components/consent-widget.md +0 -121
  187. package/docs/shared/react/components/dev-tools.md +0 -81
  188. package/docs/shared/react/components/frame.md +0 -52
  189. package/docs/shared/react/guides/building-headless-components.md +0 -110
  190. package/docs/shared/react/guides/callbacks.md +0 -89
  191. package/docs/shared/react/guides/headless.md +0 -31
  192. package/docs/shared/react/guides/iframe-blocking.md +0 -65
  193. package/docs/shared/react/guides/internationalization.md +0 -123
  194. package/docs/shared/react/guides/network-blocker.md +0 -72
  195. package/docs/shared/react/guides/optimization.md +0 -44
  196. package/docs/shared/react/guides/policy-packs.md +0 -173
  197. package/docs/shared/react/guides/script-loader.md +0 -311
  198. package/docs/shared/react/hooks/use-color-scheme.md +0 -31
  199. package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
  200. package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
  201. package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
  202. package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
  203. package/docs/shared/react/hooks/use-draggable.md +0 -30
  204. package/docs/shared/react/hooks/use-focus-trap.md +0 -20
  205. package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
  206. package/docs/shared/react/hooks/use-ssr-status.md +0 -16
  207. package/docs/shared/react/hooks/use-text-direction.md +0 -38
  208. package/docs/shared/react/hooks/use-translations.md +0 -15
  209. package/docs/shared/react/iab/consent-banner.md +0 -60
  210. package/docs/shared/react/iab/consent-dialog.md +0 -76
  211. package/docs/shared/react/iab/overview.md +0 -80
  212. package/docs/shared/react/iab/use-gvl-data.md +0 -21
  213. package/docs/shared/react/styling/classnames.md +0 -93
  214. package/docs/shared/react/styling/color-scheme.md +0 -35
  215. package/docs/shared/react/styling/css-variables.md +0 -53
  216. package/docs/shared/react/styling/overview.md +0 -261
  217. package/docs/shared/react/styling/slots.md +0 -93
  218. package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
  219. package/docs/shared/react/styling/tailwind.md +0 -88
  220. package/docs/shared/react/styling/tokens.md +0 -155
  221. package/docs/shared/troubleshooting.md +0 -82
@@ -1,299 +1,225 @@
1
1
  ---
2
- title: Styling Overview
3
- description: Five approaches for theming consent components — design tokens,
4
- component slots, CSS variables, className, and noStyle mode.
2
+ title: Styling
3
+ description: Import the Next.js stylesheet and theme c15t components with
4
+ tokens, slots, and class names through ConsentRoot options.
5
5
  group: frameworks
6
6
  ---
7
- c15t's theming system gives you multiple levels of control, but most customization should stay inside the pre-built components.
8
7
 
9
- Start with the lowest-power tool that solves the problem:
8
+ ## Stylesheet
10
9
 
11
- 1. **Pre-built component APIs** — provider options and component props such as `layout`, `direction`, `primaryButton`, `legalLinks`, and `theme.consentActions`
12
- 2. **Design tokens** — global colors, typography, spacing, radius, shadows, and motion
13
- 3. **Slots** — targeted styling for specific parts such as the banner card, footer, or title
14
- 4. **CSS variables or className-level overrides** — when you need to integrate with external CSS systems
15
- 5. **Compound components** — when you must rearrange markup while still using c15t primitives
16
- 6. **`noStyle`** — when you want c15t structure but you need to own all visual styling
17
- 7. **Headless** — when you want fully custom markup and behavior
10
+ Import c15t once from the global stylesheet loaded by `app/layout.tsx` in the
11
+ App Router or `pages/_app.tsx` in the Pages Router. With Tailwind CSS 4, place
12
+ it after the Tailwind import so the component layers keep their order:
18
13
 
19
- Keep styling and escalation as separate decisions:
20
-
21
- * If you are still using the stock banner, dialog, or widget, stay with props, tokens, and slots.
22
- * Escalate to compound components, `noStyle`, or headless only when the structure or behavior itself must change.
23
-
24
- ## Styling Approaches
25
-
26
- |Approach|Control|Use When|
27
- |--|--|--|
28
- |**Component and provider APIs**|High|Reordering actions, changing button emphasis, configuring links, hiding branding, changing copy via `i18n`|
29
- |**Tokens**|High|Changing global colors, typography, spacing, radius, shadows, or motion|
30
- |**Slots**|Medium|Targeting specific component parts (for example `consentBannerFooter` or `consentDialogCard`)|
31
- |**CSS variables / className**|Medium|Integrating with an existing stylesheet or utility classes after tokens and slots|
32
- |**Compound components**|Structure|Rearranging existing c15t primitives without going fully custom|
33
- |**noStyle**|Full visuals|Keeping c15t structure but replacing all visual defaults|
34
- |**Headless**|Full|Replacing both markup and behavior|
35
-
36
- ## Quick Start
37
-
38
- ```tsx
39
- import { type Theme, ConsentManagerProvider, ConsentBanner, ConsentDialog } from '@c15t/nextjs';
40
-
41
- const theme = {
42
- colors: {
43
- primary: '#6366f1',
44
- primaryHover: '#4f46e5',
45
- },
46
- radius: {
47
- md: '0.75rem',
48
- lg: '1rem',
49
- },
50
- slots: {
51
- consentBannerTitle: 'text-xl font-semibold',
52
- buttonPrimary: 'rounded-full',
53
- },
54
- } satisfies Theme;
55
-
56
- export function ConsentManager({ children }) {
57
- return (
58
- <ConsentManagerProvider
59
- options={{
60
- mode: 'hosted',
61
- backendURL: '/api/c15t',
62
- theme,
63
- }}
64
- >
65
- <ConsentBanner />
66
- <ConsentDialog />
67
- {children}
68
- </ConsentManagerProvider>
69
- );
70
- }
71
- ```
72
-
73
- ## Styling Inside Pre-Built Components
74
-
75
- Start here before you consider compound components or headless mode.
76
-
77
- ### 1. Provider and component configuration
78
-
79
- Use the stock APIs first:
80
-
81
- * `layout`, `direction`, and `primaryButton` for banner action arrangement
82
- * `legalLinks` for link visibility
83
- * `hideBranding` and `showTrigger` for dialog and widget behavior
84
- * `theme.consentActions` for stock banner and dialog button treatment
85
- * `i18n` on `ConsentManagerProvider` for copy changes
86
-
87
- ```tsx
88
- <ConsentBanner layout={['customize', ['reject', 'accept']]} primaryButton="accept" />
14
+ ```css
15
+ @import 'tailwindcss';
16
+ @import 'c15t/next/styles.css';
89
17
  ```
90
18
 
91
- ### 2. Design tokens
19
+ Without Tailwind, omit its import. Keep the existing global CSS import in the
20
+ layout or `_app.tsx`. Tailwind CSS 3 uses the separate build shown below.
92
21
 
93
- Set global values for colors, typography, spacing, radius, shadows, and motion:
22
+ Every rule lives in `@layer components`, so unlayered utilities from Tailwind
23
+ v4 and atomic classes from StyleX override it without specificity tricks.
24
+ Tailwind v3 treats `@layer components` as its own directive, so import the
25
+ Tailwind 3 build from your Tailwind entry instead, between the `components`
26
+ and `utilities` directives:
94
27
 
95
- ```tsx
96
- options={{ theme: { colors: { primary: '#6366f1' } } }}
28
+ ```css
29
+ @tailwind base;
30
+ @tailwind components;
31
+ @import 'c15t/next/styles.tw3.css';
32
+ @tailwind utilities;
97
33
  ```
98
34
 
99
- Use tokens first when the change is semantic:
100
-
101
- * Banner card background -> `theme.colors.surface`
102
- * Banner footer background -> `theme.colors.surfaceHover`
103
- * Shared copy color -> `theme.colors.text` and `theme.colors.textMuted`
104
- * Primary-filled surfaces such as stock branding tags and filled actions -> `theme.colors.primary` with `theme.colors.textOnPrimary` as the matching foreground override
35
+ ## Tokens
105
36
 
106
- ```tsx
107
- options={{
108
- theme: {
109
- colors: {
110
- surface: '#ffffff',
111
- surfaceHover: '#f6f3ee',
112
- },
113
- },
114
- }}
115
- ```
37
+ The provider snippets below are partial configuration examples. Apply them in
38
+ your existing Client Component wrapper, keeping its transport, prefetch,
39
+ children and other options. `ConsentRoot` also accepts `theme` and
40
+ `components` through `options`.
116
41
 
117
- If you set `theme.colors.primary` but omit `theme.colors.textOnPrimary`, c15t derives a readable foreground automatically. Add `textOnPrimary` only when you need to force a specific branded foreground color.
42
+ Colors, radii, shadows, typography, and motion come from `--c15t-*` custom
43
+ properties. Set them on the provider through `theme`, or override the
44
+ variables directly in your CSS.
118
45
 
119
- ### 3. Component slots
46
+ React and Next.js render the theme stylesheet in the server HTML before
47
+ the banner. Pass the same theme on the server and the first client render
48
+ so your custom tokens apply before hydration. The provider's `nonce`
49
+ option also applies to this stylesheet for Content Security Policy.
120
50
 
121
- Target specific component parts via the `slots` object:
51
+ `colorScheme: 'dark'` applies dark tokens in the server HTML.
52
+ `colorScheme: 'system'` uses a CSS media query to follow the visitor's
53
+ preference before hydration. If your app manages dark mode through a
54
+ root class instead, include that class in the server HTML too.
122
55
 
123
56
  ```tsx
124
- options={{
125
- theme: {
126
- slots: {
127
- consentBannerCard: 'rounded-[28px] shadow-xl',
128
- consentBannerFooter: 'border-t border-black/10',
129
- consentBannerTitle: 'tracking-tight',
130
- },
131
- },
132
- }}
57
+ import { ConsentProvider, defineTheme } from 'c15t/next';
58
+
59
+ const theme = defineTheme({
60
+ colors: { primary: '#2f6f4e' },
61
+ radius: { lg: '4px' },
62
+ consentActions: {
63
+ primary: { variant: 'primary', mode: 'filled' },
64
+ dismiss: { variant: 'neutral', mode: 'stroke' },
65
+ },
66
+ });
67
+
68
+ <ConsentProvider options={{ mode, theme }} />;
133
69
  ```
134
70
 
135
- Use slots when the component part is right but the local styling needs adjustment.
71
+ `consentActions` decides how each action role looks: `default` applies to
72
+ every button, `primary` to whichever actions the policy or your props mark
73
+ primary, and `accept`, `reject`, `customize`, and `dismiss` to one role each.
74
+ Per-action keys win over `primary`, which wins over `default`.
136
75
 
137
- ### 4. CSS variables and className-level overrides
76
+ Banner sizing has its own variables. Override them in CSS when a variant
77
+ needs a different footprint:
138
78
 
139
- Override `--c15t-*` custom properties in your stylesheet or attach classes through slots when your app styling is driven externally.
140
-
141
- Reach for this after tokens and slots, not before.
142
-
143
- ```tsx
144
- options={{
145
- theme: {
146
- slots: {
147
- consentBannerFooter: 'bg-[var(--banner-footer)]',
148
- },
149
- },
150
- }}
151
- ```
79
+ | Variable | Default | Applies to |
80
+ | ----------------------------------- | ------- | ---------------- |
81
+ | `--consent-banner-max-width` | `440px` | `floating` cards |
82
+ | `--consent-banner-widget-max-width` | `20rem` | `widget` chips |
83
+ | `--consent-banner-wall-max-width` | `30rem` | `wall` cards |
152
84
 
153
- ## Escalating Beyond Pre-Built Components
85
+ ## Colors by consent model
154
86
 
155
- Only move up this ladder when the lower rung cannot satisfy the request.
87
+ The primary action can change while the brand color stays the same. Set
88
+ `consentActions.primary` once, then select `primaryButton` per policy as
89
+ shown in [ConsentBanner](../components/consent-banner.md#per-policy-buttons).
156
90
 
157
- ### 5. Compound components
91
+ To give opt-in and opt-out banners different colors, scope the tokens to
92
+ the root's attributes. Include hover and foreground colors when overriding
93
+ CSS tokens directly:
158
94
 
159
- Use compound components when you need to rearrange existing c15t primitives:
95
+ ```css
96
+ [data-prompt][data-model='opt-in'] {
97
+ --c15t-primary: #2f6f4e;
98
+ --c15t-primary-hover: #24563c;
99
+ --c15t-text-on-primary: #fff;
100
+ }
160
101
 
161
- ```tsx
162
- <ConsentBanner.Root>
163
- <ConsentBanner.Card>
164
- <ConsentBanner.Header>
165
- <ConsentBanner.Title />
166
- <ConsentBanner.Description />
167
- </ConsentBanner.Header>
168
- <ConsentBanner.Footer>
169
- <ConsentBanner.CustomizeButton />
170
- <ConsentBanner.FooterSubGroup>
171
- <ConsentBanner.RejectButton />
172
- <ConsentBanner.AcceptButton />
173
- </ConsentBanner.FooterSubGroup>
174
- </ConsentBanner.Footer>
175
- </ConsentBanner.Card>
176
- </ConsentBanner.Root>
102
+ [data-prompt][data-model='opt-out'] {
103
+ --c15t-primary: #6b3fa0;
104
+ --c15t-primary-hover: #55327f;
105
+ --c15t-text-on-primary: #fff;
106
+ }
177
107
  ```
178
108
 
179
- ### 6. `noStyle`
180
-
181
- Use `noStyle` only when the c15t structure is still correct but you want to replace all visual defaults:
109
+ These colors apply to the action marked primary. Button layout and color
110
+ changes do not change the policy or expire a saved choice.
182
111
 
183
- ```tsx
184
- <ConsentBanner noStyle />
185
- ```
112
+ ## Slots
186
113
 
187
- ### 7. Headless
114
+ Each component part is a slot. A slot accepts any attributes the element
115
+ takes, so the contract is the same whether you write class strings or pass an
116
+ object with `className` and `style`. Set slots on the provider under
117
+ `components`, keyed by component and part.
188
118
 
189
- Go headless only when you are replacing both markup and behavior. For that path, continue to [Headless Mode](../headless).
119
+ For a full-width notice, use the supported `bar` variant. In a Client Component
120
+ inside the existing boundary, replace the stock banner with:
190
121
 
191
- ## Common Styling Tasks
122
+ ```tsx title="components/regional-banner.tsx"
123
+ 'use client';
192
124
 
193
- ### Change the banner footer background
125
+ import { ConsentBanner, usePolicyRule } from 'c15t/next';
194
126
 
195
- ```tsx
196
- options={{
197
- theme: {
198
- colors: {
199
- surfaceHover: '#f6f3ee',
200
- },
201
- },
202
- }}
127
+ export function RegionalBanner() {
128
+ const policy = usePolicyRule();
129
+ return <ConsentBanner variant={policy?.prompt === 'notice' ? 'bar' : 'floating'} />;
130
+ }
203
131
  ```
204
132
 
205
- Use `theme.colors.surfaceHover` before trying raw CSS.
133
+ To remove the notice card's radius, add these values to the existing
134
+ `options.components.banner` slots. The root owns `data-prompt`, so the card
135
+ uses Tailwind's `group` selector to read it:
206
136
 
207
- ### Change the banner card background
208
-
209
- ```tsx
210
- options={{
211
- theme: {
212
- colors: {
213
- surface: '#fffdf8',
214
- },
137
+ ```ts
138
+ const bannerSlots = {
139
+ root: { className: 'group' },
140
+ card: { className: 'group-data-[prompt=notice]:rounded-none' },
141
+ rightLink: {
142
+ className: 'underline-offset-4 data-[right=opt-out]:text-red-700',
215
143
  },
216
- }}
217
- ```
144
+ };
218
145
 
219
- Use `theme.colors.surface` before overriding banner CSS variables directly.
220
-
221
- ### Tweak the banner card, footer, or title styling without changing markup
222
-
223
- ```tsx
224
- options={{
225
- theme: {
226
- slots: {
227
- consentBannerCard: 'rounded-[28px] shadow-xl',
228
- consentBannerFooter: 'border-t border-black/10 px-6',
229
- consentBannerTitle: 'text-xl tracking-tight',
230
- },
231
- },
232
- }}
146
+ // In the existing options.components object:
147
+ // banner: bannerSlots
233
148
  ```
234
149
 
235
- ### Change stock consent action button styles semantically
150
+ The root also carries `data-variant`, so you can restyle one shape without
151
+ touching the others. Tailwind, giving a `bar` a brand-colored top edge and
152
+ tighter text:
236
153
 
237
154
  ```tsx
238
- options={{
239
- theme: {
240
- consentActions: {
241
- default: { mode: 'stroke' },
242
- accept: { variant: 'primary', mode: 'stroke' },
243
- customize: { variant: 'neutral', mode: 'ghost' },
244
- },
245
- },
246
- }}
155
+ <ConsentProvider
156
+ options={{
157
+ mode,
158
+ presentation: { prompt: { variant: 'bar' } },
159
+ components: {
160
+ banner: {
161
+ root: { className: 'group' },
162
+ card: {
163
+ className:
164
+ 'group-data-[variant=bar]:border-t-4 group-data-[variant=bar]:border-t-emerald-600',
165
+ },
166
+ },
167
+ description: {
168
+ banner: { className: 'group-data-[variant=bar]:text-xs' },
169
+ },
170
+ },
171
+ }}
172
+ />
247
173
  ```
248
174
 
249
- Use `theme.consentActions` when you want to change the stock banner/dialog button treatment without rewriting the component layout. Policy packs still control action arrangement and primary-action hints. The theme controls whether those actions render as `stroke`, `filled`, `ghost`, or `lighter`.
250
-
251
- ### Change banner copy without replacing the component
252
-
253
- ```tsx
254
- options={{
255
- i18n: {
256
- locale: 'en',
257
- messages: {
258
- en: {
259
- cookieBanner: {
260
- title: 'We value your privacy',
261
- description: 'We use cookies to improve the site and measure performance.',
262
- },
263
- common: {
264
- acceptAll: 'Accept all',
265
- rejectAll: 'Reject all',
266
- customize: 'Manage preferences',
267
- },
268
- },
269
- },
270
- },
271
- }}
272
- ```
175
+ `data-variant` sits on the root, so child slots use Tailwind's `group`
176
+ prefix to read it.
273
177
 
274
- ### Enable dark mode safely
178
+ StyleX, spreading the result of `stylex.props()` into a slot:
275
179
 
276
180
  ```tsx
277
- options={{
278
- colorScheme: 'system',
279
- theme: {
280
- colors: { surface: '#ffffff', text: '#1f2937' },
281
- dark: { surface: '#111827', text: '#f9fafb' },
282
- },
283
- }}
181
+ import * as stylex from '@stylexjs/stylex';
182
+
183
+ const styles = stylex.create({
184
+ card: { borderRadius: 0, boxShadow: 'none' },
185
+ rightLink: { textUnderlineOffset: 4, color: 'rgb(185 28 28)' },
186
+ });
187
+
188
+ <ConsentProvider
189
+ options={{
190
+ mode,
191
+ components: {
192
+ banner: {
193
+ card: stylex.props(styles.card),
194
+ rightLink: stylex.props(styles.rightLink),
195
+ },
196
+ },
197
+ }}
198
+ />;
284
199
  ```
285
200
 
286
- > ℹ️ **Info:**
287
- > If a token change does not show up where you expect, check how that component maps tokens to CSS variables before escalating. For example, the stock banner footer background comes from colors.surfaceHover, not a separate footer token.
288
- >
289
- > ⚠️ **Warning:**
290
- > Do not jump to CSS overrides or !important because a token did not appear to work at first glance.noStyle: true removes layout and visual defaults. Treat it as an advanced opt-out, not a normal theming step.Headless mode is for replacing markup and behavior, not for styling-only requests.Use either tokens/slots or raw CSS variable overrides intentionally to avoid conflicting style sources.For dark mode, c15t supports .dark and .c15t-dark.
291
-
292
- ## API Reference
293
-
294
- |Property|Value|
295
- |:--|:--|
296
- |Type Name|\`Theme\`|
297
- |Source Path|\`./packages/ui/src/theme/types.ts\`|
298
-
299
- \*ExtractedTypeTable: Could not extract "Theme" from "./packages/ui/src/theme/types.ts" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
201
+ Set `noStyle` on a component to drop the built-in classes from every part and
202
+ keep only what your slots pass. Set `noStyle` in the provider options to do it
203
+ for every component.
204
+
205
+ Banner slot keys under `components.banner`:
206
+
207
+ | Key | Element |
208
+ | ------------- | ----------------------------------------------------------------------------------------------------------------- |
209
+ | `root` | Fixed-position wrapper carrying `data-prompt`, `data-model`, `data-variant`, `data-position`, and `data-blocking` |
210
+ | `cardShell` | Sizes the card and holds the branding tag |
211
+ | `card` | The visible card, carrying `data-state` |
212
+ | `header` | Title and description container |
213
+ | `title` | Heading |
214
+ | `footer` | Action area |
215
+ | `actions` | Group of action groups |
216
+ | `actionGroup` | One group of equally prominent actions |
217
+ | `rights` | Group of right links, rendered before the actions |
218
+ | `rightLink` | One right link, carrying `data-action="right"` and `data-right` |
219
+ | `overlay` | Backdrop shown when the banner blocks the page |
220
+
221
+ Action buttons carry `data-action` and `data-variant`, and right links carry
222
+ `data-action="right"`, so a single rule such as `[data-action='dismiss']` or
223
+ `[data-action='right']` styles one role across every surface. Right links are
224
+ underlined text by default, so the only button on a notice is the primary
225
+ action.