> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ozura.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Styling & Appearance

> Customize the look of Elements fields using the style config and global appearance options.

Elements fields render inside iframes, so you can't target them with your page's CSS. Instead, you pass a style configuration object that the SDK applies inside each iframe.

***

## Style Config Shape

```ts theme={null}
type ElementStyleConfig = {
  base?:        ElementStyle; // default state
  focus?:       ElementStyle; // when the field has focus
  invalid?:     ElementStyle; // value is present but invalid (on blur)
  complete?:    ElementStyle; // value is complete and valid (on blur)
  placeholder?: ElementStyle; // styles the placeholder text
};
```

Each key maps to an `ElementStyle` object where the keys are camelCase CSS properties.

***

## Passing Styles

**Per-element** — pass `style` in the options when creating an element:

```ts theme={null}
const cardNumber = vault.createElement('cardNumber', {
  style: {
    base:        { color: '#1a1a2e', fontSize: '15px', padding: '12px 14px' },
    focus:       { caretColor: '#6366f1', backgroundColor: '#fff' },
    invalid:     { color: '#ef4444' },
    complete:    { color: '#22c55e' },
    placeholder: { color: '#94a3b8' },
  },
});
```

**Global default** — pass `appearance` when calling `OzVault.create()`. It accepts an `Appearance` object with an optional `theme` preset and/or `variables` overrides. All elements inherit this; per-element `style` merges on top.

```ts theme={null}
const vault = await OzVault.create({
  pubKey:     'YOUR_PUB_KEY',
  sessionUrl: '/api/oz-session',
  appearance: {
    theme: 'flat',
    variables: {
      colorPrimary:     '#6366f1',
      colorText:        '#1a1a2e',
      fontFamily:       '"Inter", sans-serif',
      fontSize:         '15px',
      padding:          '12px 14px',
      colorPlaceholder: '#94a3b8',
    },
  },
});
```

### Themes

The `theme` preset provides a complete set of defaults. Available themes:

| Theme       | Description                                                                                                  |
| ----------- | ------------------------------------------------------------------------------------------------------------ |
| `'default'` | Dark text on transparent background; neutral placeholder; indigo caret                                       |
| `'night'`   | Light text on transparent background; muted placeholder; indigo caret (dark-mode optimized)                  |
| `'flat'`    | Dark text; no border radius; bottom-border-only underline style that changes color on focus/invalid/complete |

You can combine `theme` + `variables` — the theme applies first, then variables override on top.

<Note>
  **Omitting `theme` is not the same as no theme.** Passing `appearance: {}` or `appearance: { variables: { ... } }` without a `theme` key applies the `'default'` preset as a base. To render elements with no preset styling at all, omit the `appearance` prop entirely and use per-element `style` overrides.

  | `appearance` value                     | Result                                                            |
  | -------------------------------------- | ----------------------------------------------------------------- |
  | *(omitted entirely)*                   | No preset styles — element uses its minimal built-in defaults     |
  | `{}`                                   | Equivalent to `{ theme: 'default' }` — full default theme applied |
  | `{ theme: 'night' }`                   | Night theme applied                                               |
  | `{ variables: { colorText: '#333' } }` | Default theme + variable overrides                                |
</Note>

### AppearanceVariables

| Variable           | Maps to                                  |
| ------------------ | ---------------------------------------- |
| `colorText`        | `base.color`                             |
| `colorBackground`  | `base.backgroundColor`                   |
| `colorPrimary`     | `base.caretColor` and `focus.caretColor` |
| `colorDanger`      | `invalid.color`                          |
| `colorSuccess`     | `complete.color`                         |
| `colorPlaceholder` | `placeholder.color`                      |
| `fontFamily`       | `base.fontFamily`                        |
| `fontSize`         | `base.fontSize`                          |
| `fontWeight`       | `base.fontWeight`                        |
| `letterSpacing`    | `base.letterSpacing`                     |
| `lineHeight`       | `base.lineHeight`                        |
| `padding`          | `base.padding`                           |

***

## Supported Style Properties

### Typography

| Property              | CSS equivalent            |
| --------------------- | ------------------------- |
| `color`               | `color`                   |
| `fontSize`            | `font-size`               |
| `fontFamily`          | `font-family`             |
| `fontWeight`          | `font-weight`             |
| `fontStyle`           | `font-style`              |
| `fontVariant`         | `font-variant`            |
| `fontSmoothing`       | `font-smoothing`          |
| `webkitFontSmoothing` | `-webkit-font-smoothing`  |
| `mozOsxFontSmoothing` | `-moz-osx-font-smoothing` |
| `letterSpacing`       | `letter-spacing`          |
| `lineHeight`          | `line-height`             |
| `textAlign`           | `text-align`              |
| `textDecoration`      | `text-decoration`         |
| `textShadow`          | `text-shadow`             |
| `textTransform`       | `text-transform`          |

### Spacing & Box

| Property        | CSS equivalent   |
| --------------- | ---------------- |
| `padding`       | `padding`        |
| `paddingTop`    | `padding-top`    |
| `paddingRight`  | `padding-right`  |
| `paddingBottom` | `padding-bottom` |
| `paddingLeft`   | `padding-left`   |

### Background & Border

| Property                                                                        | CSS equivalent               |
| ------------------------------------------------------------------------------- | ---------------------------- |
| `backgroundColor`                                                               | `background-color`           |
| `opacity`                                                                       | `opacity`                    |
| `borderRadius`                                                                  | `border-radius`              |
| `borderTopLeftRadius`                                                           | `border-top-left-radius`     |
| `borderTopRightRadius`                                                          | `border-top-right-radius`    |
| `borderBottomLeftRadius`                                                        | `border-bottom-left-radius`  |
| `borderBottomRightRadius`                                                       | `border-bottom-right-radius` |
| `border`                                                                        | `border`                     |
| `borderColor`                                                                   | `border-color`               |
| `borderWidth`                                                                   | `border-width`               |
| `borderStyle`                                                                   | `border-style`               |
| `borderTop` / `borderRight` / `borderBottom` / `borderLeft`                     | individual side shorthands   |
| `borderTopColor` / `borderRightColor` / `borderBottomColor` / `borderLeftColor` | individual side colors       |
| `borderTopWidth` / `borderRightWidth` / `borderBottomWidth` / `borderLeftWidth` | individual side widths       |
| `borderTopStyle` / `borderRightStyle` / `borderBottomStyle` / `borderLeftStyle` | individual side styles       |
| `boxShadow`                                                                     | `box-shadow`                 |
| `outline`                                                                       | `outline`                    |
| `outlineColor`                                                                  | `outline-color`              |
| `outlineWidth`                                                                  | `outline-width`              |
| `outlineStyle`                                                                  | `outline-style`              |
| `outlineOffset`                                                                 | `outline-offset`             |

### Sizing

| Property    | CSS equivalent |
| ----------- | -------------- |
| `height`    | `height`       |
| `minHeight` | `min-height`   |
| `maxHeight` | `max-height`   |

### Caret

| Property     | CSS equivalent |
| ------------ | -------------- |
| `caretColor` | `caret-color`  |

### Transitions & Cursors

| Property     | CSS equivalent |
| ------------ | -------------- |
| `transition` | `transition`   |
| `cursor`     | `cursor`       |

<Note>
  Properties like `position`, `display`, and `width` that could affect iframe layout are not supported. Use `height` / `minHeight` to control the field's vertical size.
</Note>

<Warning>
  **CSS custom properties (`var(--token)`) are not accepted in style values.** The style sanitizer blocks all CSS function syntax, including `var()`, to prevent CSS injection through the iframe boundary. Pass literal values only:

  ```diff theme={null}
  - color: 'var(--brand-color)'
  + color: '#0057FF'
  ```

  When a value is blocked, the SDK strips it silently — no error is thrown and no console warning is emitted. The browser falls back to the element's default (unstyled) appearance for that property. If your design tokens resolve to CSS variables, resolve them to their literal values before passing them in.
</Warning>

***

## Custom Fonts

To use a custom web font inside the iframes, pass a `fonts` array to `OzVault.create()`. You can reference a Google Fonts URL:

```ts theme={null}
const vault = await OzVault.create({
  pubKey:     'YOUR_PUB_KEY',
  sessionUrl: '/api/oz-session',
  fonts: [
    {
      cssSrc: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap',
    },
  ],
  appearance: {
    variables: {
      fontFamily: "'Inter', sans-serif",
    },
  },
});
```

Or a self-hosted font:

```ts theme={null}
fonts: [
  {
    family: 'MyFont',
    src:    'url(https://yourcdn.com/fonts/myfont.woff2) format("woff2")',
    weight: '400',
    style:  'normal',
  },
],
```

***

## Complete Example

```ts theme={null}
import { OzVault } from '@ozura/elements';

const vault = await OzVault.create({
  pubKey:     'YOUR_PUB_KEY',
  sessionUrl: '/api/oz-session',
  fonts: [
    { cssSrc: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap' },
  ],
  appearance: {
    theme: 'default',
    variables: {
      fontFamily:       "'Inter', sans-serif",
      fontSize:         '15px',
      colorText:        '#111827',
      padding:          '11px 13px',
      colorBackground:  '#f9fafb',
      colorPrimary:     '#6366f1',
      colorDanger:      '#ef4444',
      colorSuccess:     '#16a34a',
      colorPlaceholder: '#9ca3af',
    },
  },
});

const cardNumber = vault.createElement('cardNumber');
const expiry     = vault.createElement('expirationDate');
const cvv        = vault.createElement('cvv', {
  style: {
    // override just the CVV field
    base: { letterSpacing: '0.15em' },
  },
});
```

***

## Reflecting State with CSS Classes

Combine the `change` event with CSS classes on your wrapper element to style the border and background based on field state:

```js theme={null}
function watchField(el, wrapperId) {
  el.on('change', ({ complete, valid, error }) => {
    const wrap = document.getElementById(wrapperId);
    wrap.classList.toggle('oz-complete', complete && valid);
    wrap.classList.toggle('oz-invalid',  !valid && error != null);
  });
  el.on('focus', () => document.getElementById(wrapperId).classList.add('oz-focused'));
  el.on('blur',  () => document.getElementById(wrapperId).classList.remove('oz-focused'));
}

watchField(cardNumber, 'card-number-wrap');
watchField(expiry,     'expiry-wrap');
watchField(cvv,        'cvv-wrap');
```

```css theme={null}
.oz-field-wrap {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  transition: border-color 0.15s;
}

.oz-field-wrap.oz-focused  { border-color: #6366f1; }
.oz-field-wrap.oz-complete { border-color: #22c55e; }
.oz-field-wrap.oz-invalid  { border-color: #ef4444; }
```

***

## Updating Styles at Runtime

Call `element.update({ style: { ... } })` to restyle a field without re-mounting it:

```ts theme={null}
// Change only the base color
cardNumber.update({ style: { base: { color: '#333' } } });

// Remove a previously set style — pass an empty bucket to clear it
cardNumber.update({ style: { base: {} } });
```

Style update semantics:

* Properties you include are merged into the current style — they replace their previous values.
* Properties previously set but **absent** from the new `style` object **retain their current values** (no keys are cleared by omission).
* To reset a specific property, pass it explicitly with an empty string: `{ base: { color: '' } }`.
* To fully reset all styles, destroy and recreate the element.
* Global vault appearance theme styles are always preserved underneath.

In React, use the `style` prop on individual field components — it is applied on every render.

***

## React

In React, pass `appearance` to `<OzElements>` and `style` to individual field components:

```tsx theme={null}
<OzElements
  pubKey="YOUR_PUB_KEY"
  sessionUrl="/api/oz-session"
  appearance={{
    theme: 'flat',
    variables: { colorPrimary: '#6366f1', fontFamily: '"Inter", sans-serif' },
  }}
>
  <OzCard
    style={{
      base:    { fontSize: '15px' },
      invalid: { color: '#ef4444' },
    }}
  />
</OzElements>
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Card Elements" icon="credit-card" href="/sdks/elements/card-elements">
    All card field options and events.
  </Card>

  <Card title="Bank Elements" icon="landmark" href="/sdks/elements/bank-elements">
    All bank field options and events.
  </Card>
</CardGroup>
