---
title: Styling Overview
description: Customize every aspect of c15t's consent components using design tokens, component slots, and CSS variables.
---
c15t's theming system gives you multiple levels of control, but most customization should stay inside the pre-built components.

Start with the lowest-power tool that solves the problem:

1. **Pre-built component APIs** — provider options and component props such as `layout`, `direction`, `primaryButton`, `legalLinks`, and `theme.consentActions`
2. **Design tokens** — global colors, typography, spacing, radius, shadows, and motion
3. **Slots** — targeted styling for specific parts such as the banner card, footer, or title
4. **CSS variables or className-level overrides** — when you need to integrate with external CSS systems
5. **Compound components** — when you must rearrange markup while still using c15t primitives
6. **`noStyle`** — when you want c15t structure but you need to own all visual styling
7. **Headless** — when you want fully custom markup and behavior

Keep styling and escalation as separate decisions:

* If you are still using the stock banner, dialog, or widget, stay with props, tokens, and slots.
* Escalate to compound components, `noStyle`, or headless only when the structure or behavior itself must change.

## Styling Approaches

| Approach                        | Control      | Use When                                                                                                   |
| ------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |
| **Component and provider APIs** | High         | Reordering actions, changing button emphasis, configuring links, hiding branding, changing copy via `i18n` |
| **Tokens**                      | High         | Changing global colors, typography, spacing, radius, shadows, or motion                                    |
| **Slots**                       | Medium       | Targeting specific component parts (for example `consentBannerFooter` or `consentDialogCard`)              |
| **CSS variables / className**   | Medium       | Integrating with an existing stylesheet or utility classes after tokens and slots                          |
| **Compound components**         | Structure    | Rearranging existing c15t primitives without going fully custom                                            |
| **noStyle**                     | Full visuals | Keeping c15t structure but replacing all visual defaults                                                   |
| **Headless**                    | Full         | Replacing both markup and behavior                                                                         |

## Quick Start

Use the `Theme` type for TypeScript autocomplete and validation:

```tsx
import { type ReactNode } from 'react';
import { type Theme, ConsentManagerProvider } from '@c15t/react';

const theme = {
  colors: {
    primary: '#6366f1',
    primaryHover: '#4f46e5',
    surface: '#ffffff',
    text: '#1f2937',
    textMuted: '#6b7280',
  },
  radius: {
    md: '0.75rem',
    lg: '1rem',
  },
  spacing: {
    md: '1.25rem',
  },
} satisfies Theme;

export function ConsentManager({ children }: { children: ReactNode }) {
  return (
    <ConsentManagerProvider
      options={{
        mode: 'hosted',
        backendURL: 'https://your-instance.c15t.dev',
        theme,
      }}
    >
      {children}
    </ConsentManagerProvider>
  );
}
```

## Styling Inside Pre-Built Components

Start here before you consider compound components or headless mode.

### 1. Provider and component configuration

Use the stock APIs first:

* `layout`, `direction`, and `primaryButton` for banner action arrangement
* `legalLinks` for link visibility
* `hideBranding` and `showTrigger` for dialog and widget behavior
* `theme.consentActions` for stock banner and dialog button treatment
* `i18n` on `ConsentManagerProvider` for copy changes

```tsx
<ConsentBanner layout={['customize', ['reject', 'accept']]} primaryButton="accept" />
```

### 2. Design tokens

Set global values for colors, typography, spacing, radius, shadows, and motion:

```tsx
options={{ theme: { colors: { primary: '#6366f1' } } }}
```

Use tokens first when the change is semantic:

* Banner card background -> `theme.colors.surface`
* Banner footer background -> `theme.colors.surfaceHover`
* Shared copy color -> `theme.colors.text` and `theme.colors.textMuted`
* Primary-filled surfaces such as stock branding tags and filled actions -> `theme.colors.primary` with `theme.colors.textOnPrimary` as the matching foreground override

```tsx
options={{
  theme: {
    colors: {
      surface: '#ffffff',
      surfaceHover: '#f6f3ee',
    },
  },
}}
```

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.

### 3. Component slots

Target specific component parts via the `slots` object:

```tsx
options={{
  theme: {
    slots: {
      consentBannerCard: 'rounded-[28px] shadow-xl',
      consentBannerFooter: 'border-t border-black/10',
      consentBannerTitle: 'tracking-tight',
    },
  },
}}
```

Use slots when the component part is right but the local styling needs adjustment.

### 4. CSS variables and className-level overrides

Override `--c15t-*` custom properties in your stylesheet or attach classes through slots when your app styling is driven externally.

Reach for this after tokens and slots, not before.

```tsx
options={{
  theme: {
    slots: {
      consentBannerFooter: 'bg-[var(--banner-footer)]',
    },
  },
}}
```

## Escalating Beyond Pre-Built Components

Only move up this ladder when the lower rung cannot satisfy the request.

### 5. Compound components

Use compound components when you need to rearrange existing c15t primitives:

```tsx
<ConsentBanner.Root>
  <ConsentBanner.Card>
    <ConsentBanner.Header>
      <ConsentBanner.Title />
      <ConsentBanner.Description />
    </ConsentBanner.Header>
    <ConsentBanner.Footer>
      <ConsentBanner.CustomizeButton />
      <ConsentBanner.FooterSubGroup>
        <ConsentBanner.RejectButton />
        <ConsentBanner.AcceptButton />
      </ConsentBanner.FooterSubGroup>
    </ConsentBanner.Footer>
  </ConsentBanner.Card>
</ConsentBanner.Root>
```

### 6. `noStyle`

Use `noStyle` only when the c15t structure is still correct but you want to replace all visual defaults:

```tsx
<ConsentBanner noStyle />
```

### 7. Headless

Go headless only when you are replacing both markup and behavior. For that path, continue to [Headless Mode](../headless).

## Common Styling Tasks

### Change the banner footer background

```tsx
options={{
  theme: {
    colors: {
      surfaceHover: '#f6f3ee',
    },
  },
}}
```

Use `theme.colors.surfaceHover` before trying raw CSS.

### Change the banner card background

```tsx
options={{
  theme: {
    colors: {
      surface: '#fffdf8',
    },
  },
}}
```

Use `theme.colors.surface` before overriding banner CSS variables directly.

### Tweak the banner card, footer, or title styling without changing markup

```tsx
options={{
  theme: {
    slots: {
      consentBannerCard: 'rounded-[28px] shadow-xl',
      consentBannerFooter: 'border-t border-black/10 px-6',
      consentBannerTitle: 'text-xl tracking-tight',
    },
  },
}}
```

### Change stock consent action button styles semantically

```tsx
options={{
  theme: {
    consentActions: {
      default: { mode: 'stroke' },
      accept: { variant: 'primary', mode: 'stroke' },
      customize: { variant: 'neutral', mode: 'ghost' },
    },
  },
}}
```

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`.

### Change banner copy without replacing the component

```tsx
options={{
  i18n: {
    locale: 'en',
    messages: {
      en: {
        cookieBanner: {
          title: 'We value your privacy',
          description: 'We use cookies to improve the site and measure performance.',
        },
        common: {
          acceptAll: 'Accept all',
          rejectAll: 'Reject all',
          customize: 'Manage preferences',
        },
      },
    },
  },
}}
```

### Enable dark mode safely

```tsx
options={{
  colorScheme: 'system',
  theme: {
    colors: { surface: '#ffffff', text: '#1f2937' },
    dark: { surface: '#111827', text: '#f9fafb' },
  },
}}
```

> ℹ️ **Info:**
> 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.
>
> ⚠️ **Warning:**
> 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.

## API Reference

| Property       | Type                                                                                                                                                                                          | Description                                     | Default | Required |
| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------- | :------ | :------: |
| colors         | ColorTokens \| undefined                                                                                                                                                                      | Color palette for light mode.                   | -       | Optional |
| dark           | ColorTokens \| undefined                                                                                                                                                                      | Dark mode color overrides.                      | -       | Optional |
| typography     | TypographyTokens \| undefined                                                                                                                                                                 | Typography settings for text elements.          | -       | Optional |
| spacing        | SpacingTokens \| undefined                                                                                                                                                                    | Spacing scale for internal padding and margins. | -       | Optional |
| radius         | RadiusTokens \| undefined                                                                                                                                                                     | Border radius scale for rounded corners.        | -       | Optional |
| shadows        | ShadowTokens \| undefined                                                                                                                                                                     | Box shadow scale for depth and elevation.       | -       | Optional |
| motion         | MotionTokens \| undefined                                                                                                                                                                     | Animation and transition timing.                | -       | Optional |
| consentActions | \{ default?: ConsentActionStyle \| undefined; accept?: ConsentActionStyle \| undefined; reject?: ConsentActionStyle \| undefined; customize?: ConsentActionStyle \| undefined; } \| undefined | Semantic button styling for consent actions.    | -       | Optional |
| slots          | ComponentSlots \| undefined                                                                                                                                                                   | Component-specific style overrides.             | -       | Optional |
