# Theming

ODUS Elements uses CSS custom properties for styling, giving you fine-grained control over every element's visual appearance. Each element renders inside its own Shadow DOM and inherits theme variables from CSS custom properties set on its host element.

You can apply a theme in two ways:

* **Globally** — `applyTheme()` sets variables on all instantiated elements at once.
* **Per-element** — `setTheme()` overrides the global theme for a single element.

## Theme Variables

The following CSS custom properties are available, shown with their default values:

### Font

| Variable             | Default                 | Description                       |
| -------------------- | ----------------------- | --------------------------------- |
| `--odus-font-family` | `system-ui, sans-serif` | Base font family for all elements |
| `--odus-font-size`   | `16px`                  | Base font size                    |

When you set `--odus-font-family` via `applyTheme()`, the corresponding Google Font is automatically loaded by injecting a `<link>` stylesheet into the document head. The font is removed when you call `resetTheme()` with `--odus-font-family` or when the checkout instance is destroyed.

Supported font families:

* `Roboto`
* `Open Sans`
* `Lato`
* `Montserrat`
* `Poppins`
* `Inter`
* `Noto Sans`
* `Source Sans Pro`
* `Raleway`
* `Ubuntu`
* `Work Sans`
* `Nunito`
* `Quicksand`
* `Rubik`
* `DM Sans`

### Colors

| Variable                  | Default   | Description        |
| ------------------------- | --------- | ------------------ |
| `--odus-color-error`      | `#dc2727` | Error state color  |
| `--odus-color-text`       | `#1a1a1a` | Default text color |
| `--odus-color-background` | `#ffffff` | Background color   |

### Borders

| Variable               | Default   | Description                          |
| ---------------------- | --------- | ------------------------------------ |
| `--odus-border-color`  | `#e0e0e0` | Default border color for inputs      |
| `--odus-border-radius` | `6px`     | Border radius for inputs and buttons |

### Spacing

| Variable            | Default | Description         |
| ------------------- | ------- | ------------------- |
| `--odus-spacing-sm` | `8px`   | Small spacing unit  |
| `--odus-spacing-md` | `16px`  | Medium spacing unit |
| `--odus-spacing-lg` | `24px`  | Large spacing unit  |

### Inputs

| Variable                           | Default                 | Description                       |
| ---------------------------------- | ----------------------- | --------------------------------- |
| `--odus-input-height`              | `44px`                  | Input field height                |
| `--odus-input-padding`             | `8px 12px`              | Input field padding               |
| `--odus-input-font-size`           | `var(--odus-font-size)` | Input text font size              |
| `--odus-input-font-weight`         | `400`                   | Input text font weight            |
| `--odus-input-letter-spacing`      | `0.02em`                | Input text letter spacing         |
| `--odus-input-line-height`         | `1.5`                   | Input text line height            |
| `--odus-input-placeholder-color`   | `#717173`               | Placeholder text color            |
| `--odus-input-placeholder-opacity` | `0.3`                   | Placeholder text opacity          |
| `--odus-input-focus-shadow`        | blue glow ring          | Box shadow applied on input focus |

### Labels

| Variable                      | Default   | Description                   |
| ----------------------------- | --------- | ----------------------------- |
| `--odus-label-font-size`      | `14px`    | Label font size               |
| `--odus-label-font-weight`    | `500`     | Label font weight             |
| `--odus-label-color`          | inherited | Label text color              |
| `--odus-label-letter-spacing` | inherited | Label letter spacing          |
| `--odus-label-line-height`    | `1.4`     | Label line height             |
| `--odus-label-margin-bottom`  | `6px`     | Space between label and input |

### Validation messages

| Variable                         | Default | Description                           |
| -------------------------------- | ------- | ------------------------------------- |
| `--odus-helper-text-line-height` | `14px`  | Height of one validation message line |
| `--odus-helper-text-space`       | `4px`   | Space reserved below a field for it   |

A validation message is drawn below its field but outside the layout, so an element never changes height when one appears or clears and nothing on your page moves. Each field reserves only `--odus-helper-text-space` — a thin strip that keeps the message off whatever follows — and the message itself overhangs into the gap you already have between fields.

That overhang paints over what sits beneath it, on the form's own background colour and without intercepting clicks, so allow roughly `16px` below each element. Every message we ship fits one line at usual widths, but a narrow element can still wrap one onto a second line. Errors and hints (such as the email "did you mean" suggestion) share one row per field, so a field looks the same height whichever it shows.

### Card & Button

| Variable                      | Default                     | Description                                       |
| ----------------------------- | --------------------------- | ------------------------------------------------- |
| `--odus-card-gap`             | `12px`                      | Gap between card sub-fields (number, expiry, CVV) |
| `--odus-button-height`        | `48px`                      | Express button height                             |
| `--odus-button-border-radius` | `var(--odus-border-radius)` | Express button border radius                      |

## Applying a Theme

### Global Theme

Use `applyTheme()` to set theme variables on all instantiated elements at once:

```
checkout.applyTheme({

  '--odus-color-text': '#f8fafc',

  '--odus-color-background': '#1e293b',

  '--odus-border-color': '#334155',

  '--odus-border-radius': '8px',

  '--odus-font-family': 'Inter',

});
```

To remove specific theme overrides and revert to defaults:

```
checkout.resetTheme({

  '--odus-color-background': '',

});
```

### Per-Element Theme

Override theme variables on a single element using `setTheme()` on the element instance:

```
checkout.elements.card.setTheme({

  '--odus-border-color': '#6366f1',

  '--odus-input-height': '52px',

});



// Reset to defaults

checkout.elements.card.resetTheme({

  '--odus-border-color': '',

  '--odus-input-height': '',

});
```

## Example: Dark Theme

```
const darkTheme = {

  '--odus-color-error': '#f87171',

  '--odus-color-text': '#f1f5f9',

  '--odus-color-background': '#0f172a',

  '--odus-border-color': '#334155',

  '--odus-border-radius': '10px',

  '--odus-input-placeholder-color': '#94a3b8',

  '--odus-input-placeholder-opacity': '0.6',

  '--odus-input-focus-shadow': '0 0 0 2px rgba(129, 140, 248, 0.4)',

  '--odus-label-color': '#cbd5e1',

};



checkout.applyTheme(darkTheme);
```

tip

Because Elements uses CSS custom properties, you can also set these variables in your own CSS stylesheets or via inline styles on the container elements. The Shadow DOM will inherit the values through the host element.

tip

Want to experiment with themes visually? Try the interactive [Elements Builder](https://docs.odus.com/docs/guides/checkout/elements/builder.md) to preview theme changes in real time and export the configuration.
