# Theming

> **NOTE — unofficial library.** `@p4n/erc8004-ui` is an independent, community-built project. It is not affiliated with, maintained by, or endorsed by the authors of ERC-8004. It reads the standard's on-chain data through public subgraphs; it does not speak for the standard.

`@p4n/erc8004-ui` uses CSS variables for theming. This gives you a set of named color and radius tokens that every component references. Override those tokens in your CSS to change the look of the entire library without touching component code.

Out of the box, the library ships with a light theme and a dark theme. No configuration required — just import the stylesheet and go. Colors use OKLCH rather than hex. OKLCH is perceptually uniform — lightening or darkening a value produces a predictable visual shift, which makes themes easier to build and tweak.

```tsx
import "@p4n/erc8004-ui/styles.css"
```

## OKLCH Color Format

All color tokens are raw [OKLCH](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch) values — three space-separated numbers for `lightness chroma hue`:

- **Lightness** — `0` (black) to `1` (white).
- **Chroma** — saturation. `0` is gray, higher values are more vivid.
- **Hue** — color angle in degrees. `260` blue, `145` green, `300` purple, `25` red-orange.

For neutral grays, chroma and hue are both `0` (e.g., `0.556 0 0` is a medium gray). Use [oklch.com](https://oklch.com) to pick values interactively.

## Playground

An interactive playground for previewing presets and seeing live token changes is available on the live site at https://erc8004-ui.vercel.app/docs/theming. The CSS shown there is exactly what you would write to reproduce a theme in your own app.

## How It Works

Every component in the library uses Tailwind classes like `bg-erc8004-card` and `text-erc8004-muted-fg` instead of hardcoded colors. These classes reference CSS variables defined under the `.erc8004` scope — a wrapper that the `ERC8004Provider` renders automatically.

Because the variables are scoped to `.erc8004`, they never conflict with your app's own styles. If your app uses shadcn, Tailwind's default palette, or any other styling system, everything coexists cleanly. Dark and light mode work by swapping the variable values when a `.dark` or `.light` class is present on an ancestor — see [Dark and Light Mode](#dark-and-light-mode) below.

## Three Ways to Customize

Pick the broadest method that does the job. Use CSS variables to retheme everything, provider `className` to scope a theme to a section of your app, or component `className` for one-off tweaks.

### Option 1 — CSS Variable Overrides — retheme everything

Override the variables in your own stylesheet. Every component picks up the changes instantly.

```css
/* your-app.css */
.erc8004 {
  --erc8004-accent: 0.55 0.25 300;   /* purple instead of blue */
  --erc8004-radius: 0.75rem;          /* rounder corners */
}
```

### Option 2 — Provider `className` — scope a theme to a subtree

The provider accepts a `className` prop that gets merged onto the `.erc8004` wrapper. Two common uses:

**Toggle light or dark mode:**

```tsx
<ERC8004Provider apiKey="..." className="dark">
  {/* dark theme active for all components inside */}
</ERC8004Provider>

<ERC8004Provider apiKey="..." className="light">
  {/* forces light theme, even inside a .dark ancestor */}
</ERC8004Provider>
```

**Apply a custom theme class:**

```css
/* Define a custom theme class */
.erc8004.my-brand {
  --erc8004-accent: 0.55 0.25 300;
  --erc8004-radius: 0.75rem;
}
```

```tsx
<ERC8004Provider apiKey="..." className="my-brand">
  {/* all components inside use the custom theme */}
</ERC8004Provider>
```

### Option 3 — Component `className` — one-off tweaks

Every component accepts a `className` prop. Your classes override the component's defaults when they target the same CSS property — padding replaces padding, background replaces background.

```tsx
<ReputationScore
  agentRegistry="eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
  agentId={888}
  className="shadow-lg rounded-2xl p-6"
/>
```

## Token Convention

Tokens follow a **background / foreground pair** pattern. The base token controls the surface color, and the `-fg` suffixed token controls the text and icon color that sits on that surface.

For example, given these variables:

```css
.erc8004 {
  --erc8004-card: 1 0 0;          /* white surface */
  --erc8004-card-fg: 0.145 0 0;   /* near-black text */
}
```

A component using `bg-erc8004-card text-erc8004-card-fg` will render dark text on a white card. Override the variables, and the component adapts — you never need to change the component itself.

## Dark and Light Mode

The default theme is light — no setup needed. Adding a `.dark` ancestor class switches components to dark mode. This is the standard Tailwind dark mode convention that most apps already use.

```html
<body class="dark">
  <!-- ERC8004 components automatically use dark colors -->
</body>
```

Adding a `.light` ancestor class explicitly forces light mode, even inside a `.dark` parent. This is useful for embedding components in a light section of an otherwise-dark app.

```html
<body class="dark">
  <!-- dark everywhere... -->

  <div class="light">
    <!-- ...except these components stay light -->
    <ERC8004Provider apiKey="...">
      <ReputationScore agentRegistry="..." agentId={888} />
    </ERC8004Provider>
  </div>
</body>
```

Either class can go on the `body` tag, a container `div`, or directly on `ERC8004Provider` via the `className` prop. If your app already handles dark mode by toggling a `.dark` class, the library follows along automatically.

**Overriding dark mode colors**

To customize specific colors in dark mode, target `.dark .erc8004`:

```css
.dark .erc8004 {
  --erc8004-accent: 0.7 0.2 260;      /* brighter blue in dark mode */
  --erc8004-card: 0.18 0.01 260;      /* slight blue tint to cards */
}
```

**Overriding light mode colors**

Similarly, to customize colors only in explicit light mode, target `.light .erc8004`:

```css
.light .erc8004 {
  --erc8004-accent: 0.5 0.22 260;     /* deeper blue in light mode */
  --erc8004-card: 0.98 0.005 80;      /* warm white cards */
}
```

## Token Reference

**Surfaces**

| Token | CSS Variable | Default (Light) | What it controls |
| --- | --- | --- | --- |
| Background | `--erc8004-bg` | `1 0 0` | Default component background |
| Foreground | `--erc8004-fg` | `0.145 0 0` | Default text color |
| Card | `--erc8004-card` | `1 0 0` | Elevated surface background (cards, panels) |
| Card foreground | `--erc8004-card-fg` | `0.145 0 0` | Text on elevated surfaces |
| Muted | `--erc8004-muted` | `0.97 0 0` | Subtle backgrounds (tags, skeletons, empty states) |
| Muted foreground | `--erc8004-muted-fg` | `0.556 0 0` | Secondary text (timestamps, descriptions, helper text) |

**Accent**

| Token | CSS Variable | Default (Light) | What it controls |
| --- | --- | --- | --- |
| Accent | `--erc8004-accent` | `0.55 0.2 260` | Brand color, primary actions, active highlights |
| Accent foreground | `--erc8004-accent-fg` | `0.985 0 0` | Text on accent surfaces |

**Semantic**

| Token | CSS Variable | Default (Light) | What it controls |
| --- | --- | --- | --- |
| Positive | `--erc8004-positive` | `0.55 0.17 145` | Positive scores, success indicators |
| Positive foreground | `--erc8004-positive-fg` | `0.985 0 0` | Text on positive surfaces |
| Negative | `--erc8004-negative` | `0.55 0.2 25` | Negative scores, error states |
| Negative foreground | `--erc8004-negative-fg` | `0.985 0 0` | Text on negative surfaces |

**Borders & Focus**

| Token | CSS Variable | Default (Light) | What it controls |
| --- | --- | --- | --- |
| Border | `--erc8004-border` | `0.922 0 0` | All borders and dividers |
| Ring | `--erc8004-ring` | `0.55 0.2 260` | Focus ring on interactive elements |

**Chart Palette**

| Token | CSS Variable | Default (Light) | What it controls |
| --- | --- | --- | --- |
| Chart 1 | `--erc8004-chart-1` | `0.55 0.2 260` | First chart color (blue) |
| Chart 2 | `--erc8004-chart-2` | `0.6 0.18 145` | Second chart color (green) |
| Chart 3 | `--erc8004-chart-3` | `0.6 0.2 25` | Third chart color (red-orange) |
| Chart 4 | `--erc8004-chart-4` | `0.65 0.2 310` | Fourth chart color (purple) |
| Chart 5 | `--erc8004-chart-5` | `0.7 0.15 70` | Fifth chart color (gold) |

**Radius**

| Token | CSS Variable | Default | What it controls |
| --- | --- | --- | --- |
| Radius | `--erc8004-radius` | `0.5rem` | Base corner radius — all sizes derive from this |

## Radius Scale

The library derives a set of radius sizes from the single `--erc8004-radius` base value:

| Class | Size | Formula |
| --- | --- | --- |
| `rounded-erc8004-sm` | 0.3rem | radius × 0.6 |
| `rounded-erc8004-md` | 0.4rem | radius × 0.8 |
| `rounded-erc8004-lg` | 0.5rem | radius × 1.0 (the base) |
| `rounded-erc8004-xl` | 0.7rem | radius × 1.4 |
| `rounded-erc8004-2xl` | 0.9rem | radius × 1.8 |

Change `--erc8004-radius` once, and the entire radius scale updates proportionally:

```css
.erc8004 {
  --erc8004-radius: 0.75rem;  /* everything gets rounder */
}
```

```css
.erc8004 {
  --erc8004-radius: 0;  /* sharp corners everywhere */
}
```

## Examples

**Match your brand color**

```css
.erc8004 {
  --erc8004-accent: 0.55 0.25 300;      /* purple */
  --erc8004-ring: 0.55 0.25 300;        /* focus rings match */
}
```

**Warm neutral palette**

```css
.erc8004 {
  --erc8004-bg: 0.98 0.005 80;          /* warm white */
  --erc8004-card: 0.96 0.008 80;        /* warm off-white */
  --erc8004-muted: 0.94 0.01 80;        /* warm gray */
  --erc8004-border: 0.9 0.01 80;        /* warm border */
}
```

**Compact with sharp corners**

```tsx
<ReputationScore
  agentRegistry="eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
  agentId={888}
  className="p-2 text-sm rounded-none"
/>
```

**Full custom theme via CSS class**

```css
/* teal-brand.css */
.erc8004.teal-brand {
  --erc8004-accent: 0.6 0.22 160;       /* teal */
  --erc8004-positive: 0.6 0.22 160;     /* match accent for positive */
  --erc8004-negative: 0.55 0.2 0;       /* warm red */
  --erc8004-border: 0.88 0.01 160;      /* subtle teal borders */
  --erc8004-radius: 1rem;               /* very rounded */
}
```

```tsx
<ERC8004Provider apiKey="your-graph-api-key" className="teal-brand">
  {/* all components use the teal theme */}
</ERC8004Provider>
```

## Provider Props

The only theming-relevant prop on `ERC8004Provider` is `className`, which gets merged onto the `.erc8004` wrapper. See the [ERC8004Provider component page](https://erc8004-ui.vercel.app/docs/components/erc8004-provider) for the full prop reference.

```tsx
<ERC8004Provider apiKey="..." className="dark my-theme">
  {children}
</ERC8004Provider>
```

## FAQ

**Does the library ship its own font?**

No. Components inherit `font-family` from their parent, so they adopt whatever typography your app uses. Set the font on `.erc8004` or any ancestor and components will follow. Some elements like numeric scores and addresses use monospace (`font-mono`) for readability, but no base font is bundled or required.

**Can I force light mode inside a dark app?**

Yes. Add `className="light"` to the provider (or any ancestor of the components you want to stay light). This works even when a higher ancestor has `.dark` set.

**Will this conflict with my app's Tailwind config?**

No. All tokens are namespaced under `erc8004-` and scoped to the `.erc8004` class. They don't touch your app's `--primary`, `--background`, or any other standard Tailwind/shadcn variables.

**Do I need Tailwind in my project to use `className`?**

Not strictly — `className` accepts any CSS class string. But the library is built with Tailwind, so overriding with Tailwind classes gives you the most predictable results since `tailwind-merge` understands the conflict resolution. If your project doesn't use Tailwind, you can still pass regular CSS classes or use the CSS variable overrides instead.

**Can I theme individual components differently?**

Yes. Wrap a subset of components in a `div` with overridden variables:

```tsx
<ERC8004Provider apiKey="...">
  {/* These use the default theme */}
  <ReputationScore agentRegistry="..." agentId={1} />

  {/* These use a custom accent */}
  <div style={{ "--erc8004-accent": "0.55 0.25 300" } as React.CSSProperties}>
    <ReputationScore agentRegistry="..." agentId={2} />
    <FeedbackList agentRegistry="..." agentId={2} />
  </div>
</ERC8004Provider>
```

Since CSS variables inherit downward, any `div` that redefines a variable creates a new scope for its children.

**What color format should I use?**

Raw OKLCH values: three space-separated numbers for lightness, chroma, and hue. For example, `0.55 0.2 260` is a medium-brightness blue. You can use any OKLCH color picker to find values. For grays, set chroma and hue to `0` (e.g., `0.5 0 0` is medium gray).

## Reference

- Live page: https://erc8004-ui.vercel.app/docs/theming
- Markdown source: https://erc8004-ui.vercel.app/docs/theming.md
