---
title: "Appearance"
description: "The payment form's themes and variables."
url: https://docs.fluveo.com/payments/fluveo-js-appearance/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/payments/fluveo-js-appearance.curl.md (cURL), https://docs.fluveo.com/payments/fluveo-js-appearance.node.md (Node.js), https://docs.fluveo.com/payments/fluveo-js-appearance.python.md (Python), https://docs.fluveo.com/payments/fluveo-js-appearance.php.md (PHP).

# Appearance

The payment form's themes and variables.

The payment form is a frame of Fluveo's, so the CSS of your page does not reach it. Its look is set in code, with the `appearance` option of `fluveo.elements()`: a theme, the variables that each change one value of it, where the labels go, how the fields join and whether the form animates. Every part is optional. [Payment Element](https://docs.fluveo.com/payments/payment-element.md) explains the form itself.

![The payment form three times, side by side, with a test card typed in: the fluveo theme, light with bordered fields; the night theme, dark; and the flat theme, with filled fields and no border.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/themes.png "The three themes")

> **For AI agents:**
>
> - Set the form's look only with `appearance`, and use only the names and values this page lists. Any other throws at the call.
> - A variable's value is a text, written as CSS writes it. Leave a variable out to keep the theme's value: never copy a default from the table into your code.
> - `elements.update({ appearance })` replaces the appearance whole, so pass every part again.

## Themes

A theme is a whole look with a name: every color, corner, border and shadow of the form at once. `theme` takes three names, and the form has `"fluveo"` when you pass none. Pick the theme that suits the background of your page, then change single values with [variables](https://docs.fluveo.com/payments/fluveo-js-appearance.md#variables).

Each photograph on this page was taken with a test key, so it shows the [test mode](https://docs.fluveo.com/payments/fluveo-js.md#test-mode) line under the fields.

### fluveo

The default, for a light page: light fields with a thin border and a soft shadow.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { theme: "fluveo" },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The payment form in the fluveo theme, with a test card typed in: light fields, each with a thin border.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/theme-fluveo.png "The fluveo theme")

### night

For a dark page: dark fields with light text. The photograph shows it on a dark background.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { theme: "night" },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The payment form in the night theme on a dark background, with a test card typed in: dark fields with light text.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/theme-night.png "The night theme")

### flat

Filled fields with no border and no shadow, taller and with rounder corners.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { theme: "flat" },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The payment form in the flat theme, with a test card typed in: filled fields with round corners and no border.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/theme-flat.png "The flat theme")

## Variables

A variable changes one value of the theme, and every part of the form that uses that value follows it. A variable you leave out keeps the theme's value. Each value is a text, written as CSS writes it, of the variable's kind: a color, a length or a font family. The reference lists [each variable's kind](https://docs.fluveo.com/payments/fluveo-js.md#form-options-appearance-variables).

- `colorPrimary`: the outline and the ring of the field in focus, the selected tab, and the open row of an accordion with its radio button.
- `colorBackground`: the surface of the fields, the tabs and the accordion rows. The labels and the error lines sit on your own page.
- `colorText`: what the buyer types, and a label above its field.
- `colorTextSecondary`: a tab that is not selected, a floating label and the icons inside the fields.
- `colorTextPlaceholder`: the placeholders.
- `colorDanger`: an error line, and the outline of the field it is about.
- `fontFamily`: the font of the form's labels, tabs, fields and messages.
- `fontSizeBase`: the size that the labels, the tabs and the error lines are worked out from.
- `spacingUnit`: the padding inside the fields and the tabs, and the gaps between them.
- `borderRadius`: the corners of the fields, the tabs and the accordion rows.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: {
    variables: {
      colorPrimary: "#0f766e",
      colorBackground: "#e0f2f1",
      spacingUnit: "4px",
      borderRadius: "10px",
    },
  },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The empty payment form with four variables set: the Card tab in a store's own main color, tinted fields, more room inside each field and rounder corners.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/variables.png "Four variables on the default theme")

The default of each variable in each theme:

| Variable | `"fluveo"` | `"night"` | `"flat"` |
| --- | --- | --- | --- |
| `colorPrimary` | `#2961b2` | `#6494db` | `#2961b2` |
| `colorBackground` | `#ffffff` | `#1c1917` | `#f2f2ee` |
| `colorText` | `#1c1917` | `#f4f2eb` | `#1c1917` |
| `colorTextSecondary` | `#57534d` | `#d6d3d1` | `#57534d` |
| `colorTextPlaceholder` | `#79716b` | `#a6a09b` | `#57534d` |
| `colorDanger` | `#c03f34` | `#de8d87` | `#c03f34` |
| `fontFamily` | `system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif` | `system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif` | `system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif` |
| `fontSizeBase` | `16px` | `16px` | `16px` |
| `spacingUnit` | `2px` | `2px` | `2px` |
| `borderRadius` | `5px` | `5px` | `12px` |

## Labels

`labels` says where the label of each field goes.

- `"above"`: over its field.
- `"floating"`: inside its field. The label rests where the placeholder would be, so the form draws no placeholder, and it moves to the top of the field when the field takes the focus or holds a value.
- `"auto"`, the default: floating with condensed inputs, above with spaced ones.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { labels: "floating" },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The payment form with floating labels and a test card typed in: each label sits small at the top of its field, above the value.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/labels-floating.png "Floating labels, once the fields hold a value")

## Inputs

`inputs` says how the fields sit together. With `"spaced"`, the default, each field is a box of its own. With `"condensed"` the fields are joined in one block, with one line between two of them in the themes that draw a border, and the lines that say what is wrong show under the block, as [Errors](https://docs.fluveo.com/payments/payment-element.md#errors) describes. Labels left at `"auto"` float in a condensed block.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { inputs: "condensed" },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The empty payment form with condensed inputs: the five fields joined in one block, each label inside its field.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/inputs-condensed.png "Condensed inputs, empty")

## Animations

The form moves a little: a field changes state over a short moment, a floating label slides to its place, the loading placeholder shimmers and the form fades in over it. `disableAnimations: true` stops all of it. The form also stops by itself for a buyer whose device asks for reduced motion, so set this only when your own page never animates.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: { disableAnimations: true },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

## The text inside the card fields

The card number, the expiration date and the security code are each a frame of their own inside the form, so the form's style does not reach them either. The form hands them four values of its look when it mounts, and again after each `elements.update()`: the font family, the text size, the text color and the placeholder color. So `fontFamily`, `fontSizeBase`, `colorText` and `colorTextPlaceholder` reach what the buyer types.

Two things to know. `fontFamily` names fonts the buyer's device has: the form loads no font file. And what the buyer types is never drawn smaller than the default `fontSizeBase`, so that a phone does not zoom the page in when a field takes the focus: a smaller base shrinks the labels, the tabs and the error lines only.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const elements = fluveo.elements({
  clientSecret,
  appearance: {
    variables: {
      fontFamily: "Georgia, serif",
      fontSizeBase: "18px",
      colorText: "#1e3a8a",
    },
  },
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
```

![The payment form with a test card typed in a serif font, larger and in a store's own text color, in the card fields as in the ZIP code.](https://docs.fluveo.com/payments/img/fluveo-js-appearance/card-fields.png "The card fields follow the font, the size and the text color")

## Change it live

[elements.update()](https://docs.fluveo.com/payments/fluveo-js.md#elements-update) changes the look of a form that is already on the page, with no reload: for a switch between a light and a dark page, or a preview of your own. Each call replaces the appearance whole, and a part the new object leaves out goes back to its default, so build the whole object each time.

*checkout.js*

```javascript
const fluveo = Fluveo("pk_test_...");
const dark = window.matchMedia("(prefers-color-scheme: dark)");
const look = () => ({
  theme: dark.matches ? "night" : "fluveo",
  labels: "floating",
});
const elements = fluveo.elements({ clientSecret, appearance: look() });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
dark.addEventListener("change", () => {
  elements.update({ appearance: look() });
});
```

## What is refused

Nothing is ignored in silence. A name or a value that `appearance` does not take throws a `FluveoIntegrationError` at the call, in `fluveo.elements()` and in `elements.update()` alike, and its message names what you passed.

| You pass | It throws |
| --- | --- |
| An `appearance` that is not an object, or a name in it that the script does not know, such as `colors` | [option_not_supported](https://docs.fluveo.com/payments/fluveo-js-errors.md#option_not_supported) |
| A `theme`, a `labels` or an `inputs` outside its list, or a `disableAnimations` that is not `true` or `false` | [option_not_supported](https://docs.fluveo.com/payments/fluveo-js-errors.md#option_not_supported) |
| A name in `variables` other than the ten above | [option_not_supported](https://docs.fluveo.com/payments/fluveo-js-errors.md#option_not_supported) |
| A variable's value that is not a text, such as the number `4` | [appearance_value_invalid](https://docs.fluveo.com/payments/fluveo-js-errors.md#appearance_value_invalid) |
| A color that CSS does not have, or `var()`, `url()`, `inherit` or `currentColor` in its place | [appearance_value_invalid](https://docs.fluveo.com/payments/fluveo-js-errors.md#appearance_value_invalid) |
| A length with no unit, other than `"0"`, in a unit other than `px`, `rem` or `em`, or with more than three digits or two decimals | [appearance_value_invalid](https://docs.fluveo.com/payments/fluveo-js-errors.md#appearance_value_invalid) |
| A font family with a `url()` in it, or longer than 200 characters | [appearance_value_invalid](https://docs.fluveo.com/payments/fluveo-js-errors.md#appearance_value_invalid) |
| `appearance` in `element.update()` | [option_not_supported](https://docs.fluveo.com/payments/fluveo-js-errors.md#option_not_supported): it goes to `elements.update()` |
