@c15t/react 2.0.0-rc.6 → 2.0.0-rc.7

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 (47) hide show
  1. package/dist/components/consent-banner/atoms/root.cjs +1 -1
  2. package/dist/components/consent-banner/atoms/root.js +1 -1
  3. package/dist/components/consent-dialog/atoms/root.cjs +1 -1
  4. package/dist/components/consent-dialog/atoms/root.js +1 -1
  5. package/dist/components/consent-widget/atoms/accordion.cjs +1 -1
  6. package/dist/components/consent-widget/atoms/accordion.js +1 -1
  7. package/dist/components/iab-consent-banner/atoms/card.cjs +1 -1
  8. package/dist/components/iab-consent-banner/atoms/card.js +1 -1
  9. package/dist/components/iab-consent-banner/atoms/footer.cjs +1 -1
  10. package/dist/components/iab-consent-banner/atoms/footer.js +1 -1
  11. package/dist/components/iab-consent-banner/atoms/header.cjs +1 -1
  12. package/dist/components/iab-consent-banner/atoms/header.js +1 -1
  13. package/dist/components/iab-consent-banner/atoms/root.cjs +1 -1
  14. package/dist/components/iab-consent-banner/atoms/root.js +1 -1
  15. package/dist/components/iab-consent-dialog/atoms/card.cjs +1 -1
  16. package/dist/components/iab-consent-dialog/atoms/card.js +1 -1
  17. package/dist/components/iab-consent-dialog/atoms/footer.cjs +1 -1
  18. package/dist/components/iab-consent-dialog/atoms/footer.js +1 -1
  19. package/dist/components/iab-consent-dialog/atoms/header.cjs +1 -1
  20. package/dist/components/iab-consent-dialog/atoms/header.js +1 -1
  21. package/dist/components/iab-consent-dialog/atoms/root.cjs +1 -1
  22. package/dist/components/iab-consent-dialog/atoms/root.js +1 -1
  23. package/dist/components/shared/primitives/box.cjs +1 -1
  24. package/dist/components/shared/primitives/box.js +1 -1
  25. package/dist/iab/styles.tw3.css +1 -0
  26. package/dist/styles.tw3.css +1 -0
  27. package/dist/version.cjs +1 -1
  28. package/dist/version.js +1 -1
  29. package/dist-types/components/consent-banner/atoms/root.d.ts +43 -12
  30. package/dist-types/components/consent-banner/index.d.ts +44 -24
  31. package/dist-types/components/consent-dialog/index.d.ts +29 -8
  32. package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +0 -1
  33. package/dist-types/components/consent-widget/atoms/accordion.d.ts +4 -3
  34. package/dist-types/components/consent-widget/index.d.ts +23 -6
  35. package/dist-types/version.d.ts +1 -1
  36. package/docs/building-headless-components.md +3 -0
  37. package/docs/components/consent-banner.md +68 -18
  38. package/docs/components/consent-dialog.md +31 -2
  39. package/docs/components/consent-widget.md +31 -2
  40. package/docs/headless.md +13 -7
  41. package/docs/styling/classnames.md +17 -9
  42. package/docs/styling/overview.md +166 -29
  43. package/docs/styling/slots.md +37 -7
  44. package/docs/styling/tailwind.md +12 -20
  45. package/package.json +6 -2
  46. package/src/iab/styles.tw3.css +10 -0
  47. package/src/styles.tw3.css +10 -0
@@ -2,24 +2,34 @@
2
2
  title: Styling Overview
3
3
  description: Customize every aspect of c15t's consent components using design tokens, component slots, and CSS variables.
4
4
  ---
5
- c15t's theming system gives you multiple levels of control, from high-level design tokens to complete style removal.
5
+ c15t's theming system gives you multiple levels of control, but most customization should stay inside the pre-built components.
6
6
 
7
- The flow:
7
+ Start with the lowest-power tool that solves the problem:
8
8
 
9
- 1. **Define** tokens (colors, spacing, radius, etc.) in JavaScript
10
- 2. Tokens are **injected** as CSS custom properties (`--c15t-*`) at runtime
11
- 3. Components **consume** these variables in their default styles
12
- 4. You **override** at any level: tokens, slots, CSS variables, or raw classNames
9
+ 1. **Pre-built component APIs** provider options and component props such as `layout`, `direction`, `primaryButton`, `legalLinks`, and `theme.consentActions`
10
+ 2. **Design tokens** global colors, typography, spacing, radius, shadows, and motion
11
+ 3. **Slots** targeted styling for specific parts such as the banner card, footer, or title
12
+ 4. **CSS variables or className-level overrides** when you need to integrate with external CSS systems
13
+ 5. **Compound components** — when you must rearrange markup while still using c15t primitives
14
+ 6. **`noStyle`** — when you want c15t structure but you need to own all visual styling
15
+ 7. **Headless** — when you want fully custom markup and behavior
16
+
17
+ Keep styling and escalation as separate decisions:
18
+
19
+ * If you are still using the stock banner, dialog, or widget, stay with props, tokens, and slots.
20
+ * Escalate to compound components, `noStyle`, or headless only when the structure or behavior itself must change.
13
21
 
14
22
  ## Styling Approaches
15
23
 
16
24
  |Approach|Control|Use When|
17
25
  |--|--|--|
26
+ |**Component and provider APIs**|High|Reordering actions, changing button emphasis, configuring links, hiding branding, changing copy via `i18n`|
18
27
  |**Tokens**|High|Changing global colors, typography, spacing, radius, shadows, or motion|
19
- |**Slots**|Medium|Targeting specific component parts (e.g., the banner title, dialog footer)|
20
- |**CSS Variables**|Medium|Overriding `--c15t-*` variables from external CSS|
21
- |**className**|Medium|Passing class names to components or slots|
22
- |**noStyle**|Full|Removing all default styles, building from scratch|
28
+ |**Slots**|Medium|Targeting specific component parts (for example `consentBannerFooter` or `consentDialogCard`)|
29
+ |**CSS variables / className**|Medium|Integrating with an existing stylesheet or utility classes after tokens and slots|
30
+ |**Compound components**|Structure|Rearranging existing c15t primitives without going fully custom|
31
+ |**noStyle**|Full visuals|Keeping c15t structure but replacing all visual defaults|
32
+ |**Headless**|Full|Replacing both markup and behavior|
23
33
 
24
34
  ## Quick Start
25
35
 
@@ -61,9 +71,25 @@ export function ConsentManager({ children }: { children: ReactNode }) {
61
71
  }
62
72
  ```
63
73
 
64
- ## Styling Paths
74
+ ## Styling Inside Pre-Built Components
75
+
76
+ Start here before you consider compound components or headless mode.
77
+
78
+ ### 1. Provider and component configuration
79
+
80
+ Use the stock APIs first:
81
+
82
+ * `layout`, `direction`, and `primaryButton` for banner action arrangement
83
+ * `legalLinks` for link visibility
84
+ * `hideBranding` and `showTrigger` for dialog and widget behavior
85
+ * `theme.consentActions` for stock banner and dialog button treatment
86
+ * `i18n` on `ConsentManagerProvider` for copy changes
87
+
88
+ ```tsx
89
+ <ConsentBanner layout={['customize', ['reject', 'accept']]} primaryButton="accept" />
90
+ ```
65
91
 
66
- ### 1. Design tokens
92
+ ### 2. Design tokens
67
93
 
68
94
  Set global values for colors, typography, spacing, radius, shadows, and motion:
69
95
 
@@ -71,55 +97,140 @@ Set global values for colors, typography, spacing, radius, shadows, and motion:
71
97
  options={{ theme: { colors: { primary: '#6366f1' } } }}
72
98
  ```
73
99
 
74
- ### 2. Component slots
100
+ Use tokens first when the change is semantic:
101
+
102
+ * Banner card background -> `theme.colors.surface`
103
+ * Banner footer background -> `theme.colors.surfaceHover`
104
+ * Shared copy color -> `theme.colors.text` and `theme.colors.textMuted`
105
+
106
+ ```tsx
107
+ options={{
108
+ theme: {
109
+ colors: {
110
+ surface: '#ffffff',
111
+ surfaceHover: '#f6f3ee',
112
+ },
113
+ },
114
+ }}
115
+ ```
116
+
117
+ ### 3. Component slots
75
118
 
76
119
  Target specific component parts via the `slots` object:
77
120
 
78
121
  ```tsx
79
- options={{ theme: { slots: { consentBannerTitle: 'text-2xl font-bold' } } }}
122
+ options={{
123
+ theme: {
124
+ slots: {
125
+ consentBannerCard: 'rounded-[28px] shadow-xl',
126
+ consentBannerFooter: 'border-t border-black/10',
127
+ consentBannerTitle: 'tracking-tight',
128
+ },
129
+ },
130
+ }}
80
131
  ```
81
132
 
82
- ### 3. CSS variables
133
+ Use slots when the component part is right but the local styling needs adjustment.
83
134
 
84
- Override `--c15t-*` custom properties in your stylesheet.
135
+ ### 4. CSS variables and className-level overrides
85
136
 
86
- ### 4. className prop
137
+ Override `--c15t-*` custom properties in your stylesheet or attach classes through slots when your app styling is driven externally.
87
138
 
88
- Pass className directly to components:
139
+ Reach for this after tokens and slots, not before.
89
140
 
90
141
  ```tsx
91
- <ConsentBanner className="my-custom-banner" />
142
+ options={{
143
+ theme: {
144
+ slots: {
145
+ consentBannerFooter: 'bg-[var(--banner-footer)]',
146
+ },
147
+ },
148
+ }}
92
149
  ```
93
150
 
94
- ### 5. noStyle prop
151
+ ## Escalating Beyond Pre-Built Components
152
+
153
+ Only move up this ladder when the lower rung cannot satisfy the request.
95
154
 
96
- Strip all default styles and build from scratch (best paired with [Headless Mode](../headless)):
155
+ ### 5. Compound components
156
+
157
+ Use compound components when you need to rearrange existing c15t primitives:
158
+
159
+ ```tsx
160
+ <ConsentBanner.Root>
161
+ <ConsentBanner.Card>
162
+ <ConsentBanner.Header>
163
+ <ConsentBanner.Title />
164
+ <ConsentBanner.Description />
165
+ </ConsentBanner.Header>
166
+ <ConsentBanner.Footer>
167
+ <ConsentBanner.CustomizeButton />
168
+ <ConsentBanner.FooterSubGroup>
169
+ <ConsentBanner.RejectButton />
170
+ <ConsentBanner.AcceptButton />
171
+ </ConsentBanner.FooterSubGroup>
172
+ </ConsentBanner.Footer>
173
+ </ConsentBanner.Card>
174
+ </ConsentBanner.Root>
175
+ ```
176
+
177
+ ### 6. `noStyle`
178
+
179
+ Use `noStyle` only when the c15t structure is still correct but you want to replace all visual defaults:
97
180
 
98
181
  ```tsx
99
182
  <ConsentBanner noStyle />
100
183
  ```
101
184
 
185
+ ### 7. Headless
186
+
187
+ Go headless only when you are replacing both markup and behavior. For that path, continue to [Headless Mode](../headless).
188
+
102
189
  ## Common Styling Tasks
103
190
 
104
- ### Change brand color globally
191
+ ### Change the banner footer background
105
192
 
106
193
  ```tsx
107
- options={{ theme: { colors: { primary: '#0ea5e9', primaryHover: '#0284c7' } } }}
194
+ options={{
195
+ theme: {
196
+ colors: {
197
+ surfaceHover: '#f6f3ee',
198
+ },
199
+ },
200
+ }}
108
201
  ```
109
202
 
110
- ### Make the banner card more compact
203
+ Use `theme.colors.surfaceHover` before trying raw CSS.
204
+
205
+ ### Change the banner card background
111
206
 
112
207
  ```tsx
113
- options={{ theme: { spacing: { md: '0.75rem', lg: '1rem' } } }}
208
+ options={{
209
+ theme: {
210
+ colors: {
211
+ surface: '#fffdf8',
212
+ },
213
+ },
214
+ }}
114
215
  ```
115
216
 
116
- ### Round primary/secondary buttons
217
+ Use `theme.colors.surface` before overriding banner CSS variables directly.
218
+
219
+ ### Tweak the banner card, footer, or title styling without changing markup
117
220
 
118
221
  ```tsx
119
- options={{ theme: { slots: { buttonPrimary: 'rounded-full', buttonSecondary: 'rounded-full' } } }}
222
+ options={{
223
+ theme: {
224
+ slots: {
225
+ consentBannerCard: 'rounded-[28px] shadow-xl',
226
+ consentBannerFooter: 'border-t border-black/10 px-6',
227
+ consentBannerTitle: 'text-xl tracking-tight',
228
+ },
229
+ },
230
+ }}
120
231
  ```
121
232
 
122
- ### Change consent action button styles semantically
233
+ ### Change stock consent action button styles semantically
123
234
 
124
235
  ```tsx
125
236
  options={{
@@ -135,6 +246,29 @@ options={{
135
246
 
136
247
  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`.
137
248
 
249
+ ### Change banner copy without replacing the component
250
+
251
+ ```tsx
252
+ options={{
253
+ i18n: {
254
+ locale: 'en',
255
+ messages: {
256
+ en: {
257
+ cookieBanner: {
258
+ title: 'We value your privacy',
259
+ description: 'We use cookies to improve the site and measure performance.',
260
+ },
261
+ common: {
262
+ acceptAll: 'Accept all',
263
+ rejectAll: 'Reject all',
264
+ customize: 'Manage preferences',
265
+ },
266
+ },
267
+ },
268
+ },
269
+ }}
270
+ ```
271
+
138
272
  ### Enable dark mode safely
139
273
 
140
274
  ```tsx
@@ -147,8 +281,11 @@ options={{
147
281
  }}
148
282
  ```
149
283
 
284
+ > ℹ️ **Info:**
285
+ > 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.
286
+ >
150
287
  > ⚠️ **Warning:**
151
- > noStyle: true removes layout and visual defaults. Use it only when you want full control.Use either tokens/slots or raw CSS variable overrides intentionally to avoid conflicting style sources.For dark mode, c15t supports .dark and .c15t-dark.
288
+ > 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.
152
289
 
153
290
  ## API Reference
154
291
 
@@ -4,7 +4,19 @@ description: Target individual component parts with styles using the slot system
4
4
  ---
5
5
  ## What are Slots?
6
6
 
7
- Slots let you target specific parts of consent components with styles. Each component is built from named "slots" (e.g., `consentBannerTitle`, `consentDialogFooter`) that you can style individually.
7
+ Slots let you target specific parts of consent components with styles. Each component is built from named slots such as `consentBannerTitle` and `consentDialogFooter`.
8
+
9
+ Use slots after the stock component APIs and design tokens:
10
+
11
+ * If the change is semantic, prefer tokens first. For example, the stock banner footer background comes from `theme.colors.surfaceHover`.
12
+ * If the component part is correct but you need a local tweak, use a slot.
13
+
14
+ Common banner slot choices:
15
+
16
+ * `consentBannerCard` for card radius, shadow, width, and local background treatment
17
+ * `consentBannerFooter` for spacing, borders, and local footer styling
18
+ * `consentBannerTitle` for title typography
19
+ * `buttonPrimary` and `buttonSecondary` for shared button classes
8
20
 
9
21
  ## Using Slots
10
22
 
@@ -13,8 +25,8 @@ Pass slot styles in the theme's `slots` object:
13
25
  ```tsx
14
26
  const theme = {
15
27
  slots: {
16
- // String value = className
17
- consentBannerTitle: 'text-xl font-bold text-gray-900',
28
+ consentBannerFooter: 'border-t border-black/10 px-6',
29
+ consentBannerTitle: 'text-xl font-bold tracking-tight',
18
30
 
19
31
  // Object value = className + inline styles
20
32
  consentBannerCard: {
@@ -34,13 +46,31 @@ Each slot accepts either a `string` (treated as className) or a `SlotStyle` obje
34
46
  consentBannerTitle: 'my-custom-class'
35
47
 
36
48
  // Object: className + style + noStyle
37
- consentBannerTitle: {
38
- className: 'my-custom-class',
39
- style: { color: 'red', fontSize: '1.5rem' },
40
- noStyle: false, // Set true to remove default styles for this slot
49
+ consentBannerFooter: {
50
+ className: 'border-t border-black/10',
51
+ style: { paddingBlock: '1rem' },
52
+ noStyle: false, // Set true only when you want to remove this slot's default styling
41
53
  }
42
54
  ```
43
55
 
56
+ `noStyle` on a slot is an advanced escape hatch. Start with className and style overrides first.
57
+
58
+ ## Example: Style the stock banner without changing markup
59
+
60
+ ```tsx
61
+ const theme = {
62
+ colors: {
63
+ surface: '#fffdf8',
64
+ surfaceHover: '#f6f3ee',
65
+ },
66
+ slots: {
67
+ consentBannerCard: 'rounded-[28px] shadow-xl',
68
+ consentBannerFooter: 'border-t border-black/10 px-6',
69
+ consentBannerTitle: 'tracking-tight',
70
+ },
71
+ } satisfies Theme;
72
+ ```
73
+
44
74
  ## Available Slots
45
75
 
46
76
  Use the typed API reference below for the full slot list and descriptions. It stays in sync with the actual component slot surface.
@@ -18,40 +18,32 @@ import '@c15t/nextjs/styles.css';
18
18
 
19
19
  ### Tailwind v4
20
20
 
21
- Tailwind v4 automatically scans your source files. Declare c15t's layer order once in your global CSS so utilities stay last:
21
+ Tailwind v4 automatically scans your source files. Import Tailwind normally. c15t component styles join Tailwind's `components` layer automatically, so no extra c15t-specific layer declaration is needed:
22
22
 
23
23
  ```css
24
- @layer theme, base, components, c15t, utilities;
25
24
  @import "tailwindcss";
26
25
  ```
27
26
 
28
27
  ### Tailwind v3
29
28
 
30
- Keep Tailwind's directives in your app stylesheet, but wrap `@tailwind base` in a native `base` layer so c15t's `@layer c15t` rules can sit above Preflight:
29
+ Import the Tailwind 3-compatible c15t stylesheet before your app Tailwind globals, then keep your standard Tailwind directives in the app stylesheet:
31
30
 
32
- ```css title="app/globals.css"
33
- @layer base, components, c15t;
31
+ ```tsx title="app/layout.tsx"
32
+ import '@c15t/react/styles.tw3.css';
33
+ import './globals.css';
34
+ ```
34
35
 
35
- @layer base {
36
- @tailwind base;
37
- }
36
+ ```tsx title="app/layout.tsx"
37
+ import '@c15t/nextjs/styles.tw3.css';
38
+ import './globals.css';
39
+ ```
38
40
 
41
+ ```css title="app/globals.css"
42
+ @tailwind base;
39
43
  @tailwind components;
40
44
  @tailwind utilities;
41
45
  ```
42
46
 
43
- Then add c15t's component paths to your `content` array:
44
-
45
- ```js title="tailwind.config.js"
46
- module.exports = {
47
- content: [
48
- './src/**/*.{js,ts,jsx,tsx}',
49
- './node_modules/@c15t/react/**/*.{js,mjs}',
50
- './node_modules/@c15t/nextjs/**/*.{js,mjs}',
51
- ],
52
- };
53
- ```
54
-
55
47
  ## Using Tailwind with Slots
56
48
 
57
49
  Apply Tailwind classes via the theme's `slots` object:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c15t/react",
3
- "version": "2.0.0-rc.6",
3
+ "version": "2.0.0-rc.7",
4
4
  "description": "Developer-first CMP for React: cookie banner, consent manager, preferences centre. GDPR ready with minimal setup and rich customization",
5
5
  "keywords": [
6
6
  "react",
@@ -32,7 +32,9 @@
32
32
  "type": "module",
33
33
  "exports": {
34
34
  "./styles.css": "./dist/styles.css",
35
+ "./styles.tw3.css": "./src/styles.tw3.css",
35
36
  "./iab/styles.css": "./dist/iab/styles.css",
37
+ "./iab/styles.tw3.css": "./src/iab/styles.tw3.css",
36
38
  "./primitives": {
37
39
  "types": "./dist/primitives.d.ts",
38
40
  "import": "./dist/primitives.js",
@@ -137,6 +139,8 @@
137
139
  "docs",
138
140
  "dist-types",
139
141
  "client",
142
+ "src/styles.tw3.css",
143
+ "src/iab/styles.tw3.css",
140
144
  "!dist/mockServiceWorker.js"
141
145
  ],
142
146
  "scripts": {
@@ -158,7 +162,7 @@
158
162
  "not op_mini all"
159
163
  ],
160
164
  "dependencies": {
161
- "@c15t/ui": "2.0.0-rc.6",
165
+ "@c15t/ui": "2.0.0-rc.7",
162
166
  "c15t": "2.0.0-rc.6",
163
167
  "clsx": "2.1.1"
164
168
  },
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @c15t/react/iab — Tailwind 3-compatible IAB component styles.
3
+ *
4
+ * Import this stylesheet before your app Tailwind globals so utility classes
5
+ * can come after the c15t base rules.
6
+ *
7
+ * Usage:
8
+ * import '@c15t/react/iab/styles.tw3.css';
9
+ */
10
+ @import "@c15t/ui/iab/styles.tw3.css";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @c15t/react — Tailwind 3-compatible prebuilt component styles.
3
+ *
4
+ * Import this stylesheet before your app Tailwind globals so utility classes
5
+ * can come after the c15t base rules.
6
+ *
7
+ * Usage:
8
+ * import '@c15t/react/styles.tw3.css';
9
+ */
10
+ @import "@c15t/ui/styles.tw3.css";