Skip to content

Appearance

Make the quote look like your own product team built it.

The Appearance API

A single appearance object controls how the embedded quote and the native components look. It has five parts: theme, variables, rules, layout and fonts.

Same object, two mechanisms. For the iframe (embed.js, <cord-quote>, <CordCotizador>) the object travels to Cord’s server, which validates it and renders the CSS inside its own origin: your page never writes styles inside the iframe. For the native components (<CordBuilder> through <CordProvider appearance={...}>) the SDK applies the variables as CSS on your page. rules and layout only apply to the iframe; elements and baseTheme only to native components.

<script src="https://cordhq.app/embed.js" async></script>
<div
  data-cord-token="a1b2c3d4e5f60718"
  data-cord-appearance='{
    "theme": "flat",
    "variables": {
      "colorPrimary": "#0f766e",
      "colorText": "#0b1220",
      "borderRadius": "10px",
      "borderRadiusButton": "999px"
    },
    "rules": {
      "Button": { "text-transform": "uppercase", "letter-spacing": "0.04em" },
      "Total": { "font-weight": "700" }
    },
    "layout": { "compact": true, "hideChat": true },
    "fonts": [{ "cssSrc": "https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" }]
  }'>
</div>

With the Web Component, the same JSON goes in the appearance attribute or the element.appearance property; in React, in the appearance prop of <CordCotizador>.

Themes (theme)

Theme What it does
light Default.
dark Full dark palette: background, surfaces, text, borders and fields. night is an alias.
auto Follows the visitor’s prefers-color-scheme.
flat No shadow and visible borders, for sites that don’t use elevation.

The theme is applied first, and your variables always win over it.

Variables (variables)

Written in camelCase. Each one reaches a real surface of the quote; a variable you don’t set keeps Cord’s value.

Variable Type Where it shows
colorPrimary color Primary button, accents, your own chat bubbles
colorOnPrimary color Text on the primary color
colorBackground color Card background
colorSurface color Inner panels: notes, total, chat, notices
colorText color Main text and amounts
colorTextSecondary color Labels, tax ID, notes
colorTextPlaceholder color Table headers, hints, placeholders
colorBorder color Dividers and borders
colorDanger color Reject and errors
colorSuccess color Confirmations
colorInput color Field background
colorInputText color Field text
colorInputBorder color Field border
colorFocus color Focused field border
fontFamily family The whole card
fontSize length Line items
fontWeightBold weight Buttons
borderRadius length Card
borderRadiusButton length Buttons
borderRadiusInput length Fields
spacingCard spacing Card padding (2rem or 1.5rem 2rem)
shadowCard none or default Card shadow

A color accepts hex, rgb(), hsl(), oklch(), oklab(), lab(), lch() or a name. A length accepts px, rem, em or %.

Per-component rules (rules)

When variables aren’t enough, rules applies properties to components with public names. They are not CSS selectors: they are stable names Cord maps to its markup, so they don’t break when the markup changes.

"rules": {
  "Button": { "text-transform": "uppercase" },
  "Button:hover": { "opacity": "0.9" },
  "Input:focus": { "border-color": "#0f766e" },
  "Bubble--mine": { "background-color": "#0f766e" }
}

Components: Card, Header, Total, Table, Row, SummaryRow, Notes, Button, Button:hover, ButtonSecondary, ButtonSecondary:hover, Input, Input:focus, Chat, Bubble, Bubble--mine.

Properties: color, background-color, border-color, border-width, border-style, border-radius, font-size, font-weight, letter-spacing, text-transform, padding, box-shadow (none or default) and opacity.

Layout (layout)

Option Effect
compact: true Less whitespace in the card, for narrow columns.
hideChat: true Hides the conversation and per-line comments.
hideNotes: true Hides the quote’s notes block.

Hiding is presentation only: the quote and its actions are the same on the public link.

Fonts (fonts)

Up to four stylesheets from fonts.googleapis.com or fonts.bunny.net over https. If you don’t set fontFamily, Cord uses the first family of the first stylesheet.

What Cord validates and why

Every value that ends up as CSS goes through a validator with closed lists of keys, components and properties, and a grammar per value type. url(), expression(), @, !important, ;, braces and < are dropped, and the whole object is ignored above 8 KB. Dropped values don’t break the rest: they are ignored, the SDK warns about them in the console during development, and they show up in the debug bar with a test key.

This keeps appearance from being used to hide buttons, cover the total or load third-party resources inside the iframe: the design is yours, the integrity of the quote is Cord’s.

Native components

Headless mode (baseTheme: 'none')

With <CordBuilder> or useQuoteBuilder and your own UI, appearance={{ baseTheme: 'none' }} on <CordProvider> turns off the base stylesheet. The .cord-* classes stay in the markup and the look is up to you (Tailwind, CSS Modules or whatever you use).

Per-element overrides (elements)

Every node of <CordBuilder> carries a stable .cord-<key> class (builderRoot, formField, itemRow, summaryRoot, submitButton…). appearance.elements adds your className and style:

<CordProvider
  publishableKey={pk}
  appearance={{
    variables: { colorPrimary: '#0f766e', borderRadiusInput: '6px' },
    elements: {
      submitButton: 'my-button',
      itemRow: { style: { gap: '18px' } },
    },
  }}
>
  <CordBuilder />
</CordProvider>

The base .cord-<key> class is never replaced; yours is added on top.