For the complete documentation index, see llms.txt. This page is also available as Markdown.

Storefront styling guide

Purpose

This guide explains how to restyle the Returns Centre — the trade-in widget Tern renders on your storefront — so it matches the rest of your site. It applies whether Tern embeds the widget for you or you mount <tern-trade-in> yourself using one of the integration guides in this section.

The Returns Centre picks up your shop's fonts and colours automatically, but you can go further. There are two ways to change how it looks, and both live in the Tern admin under Copy Customisation:

  1. Theme settings — colours, fonts and corner rounding that restyle the whole widget consistently. No CSS knowledge needed. Start here.

  2. Custom CSS — your own style rules, for fine-grained control over individual parts of the widget.

Everything on this page is supported: it will keep working from release to release. We add new options over time, but we don't rename or remove anything listed here without telling you first.

Terminology

A few terms this guide uses precisely:

  • The widget — the Returns Centre UI, rendered inside the <tern-trade-in> element on your page. Its root element is #trn-app.

  • Theme variable — a CSS custom property (also called a CSS variable) with a --trn- prefix. These are the widget's design tokens: named values for colours, fonts and corner rounding that the whole UI reads from.

  • Styling hook — a stable class name with a .trn- prefix (for example .trn-button). These follow a BEM-flavoured naming scheme (block__element--modifier) and are the supported targets for custom CSS.

  • Utility class — a short, generated class such as mt-6 or flex. These are build output, not a stable API — see What not to target.

How your styles reach the widget

The widget renders inside a shadow root attached to the <tern-trade-in> element. Shadow DOM is the browser's style-encapsulation mechanism: styles outside it don't leak in, and the widget's styles don't leak out onto your page.

Two practical consequences:

  1. Rules in your site's own stylesheets will not restyle the widget's internals. The supported route is the Custom CSS field in Copy Customisation — Tern delivers that CSS inside the widget for you.

  2. The widget can never break your page's styling, however heavily you customise it.

Your custom CSS is applied after the widget's own styles and always takes precedence — you never need !important to override us (existing !important rules keep working fine).

For CSS experts: the widget's own styles live in named cascade layers, while your custom CSS is injected unlayered after them. Per the cascade, unlayered author styles beat layered ones regardless of specificity — that's why a plain #trn-app .trn-button { … } rule always wins.

1. Theme settings (colours, fonts, corners)

These are applied as theme variables on the widget. Most merchants set them through the theme fields in the admin; if you prefer, you can also set them yourself at the top of your custom CSS:

Colour format: colours are plain hex codes, used exactly like any other CSS colour — no rgb() wrapper needed:

Brand

Your accent colour — used for buttons and the widget's other key accents.

Variable
What it changes

--trn-brand

Buttons and key accents — your "brand" colour

--trn-on-brand

Text on those buttons

Page

Your base palette — the widget's background, card colour and main text colour.

Variable
What it changes

--trn-background

The widget's background

--trn-surface

Card and panel backgrounds (defaults to the background colour)

--trn-foreground

Your ink colour — main text, and what your greys are derived from

Status

Colours for error and success messages, and for the status badges on the trade-in history pages.

Variable
What it changes

--trn-error

Error states

--trn-success

Success states

--trn-warning

Status badge colour for waiting states (amber)

--trn-info

Status badge colour for in-progress states (blue)

Corners

Corner rounding, in three sizes.

Variable
What it changes

--trn-radius-sm

Corner rounding on small elements — inputs, tags (default 4px)

--trn-radius-md

Corner rounding on cards and dialogs (default 8px)

--trn-radius-full

The "pill" radius used by buttons (default 9999px; lower it for squarer buttons, or use --trn-button-radius to change buttons only)

Derived colours

A further seven variables are computed automatically from your foreground and background colours, so cards, borders and secondary text always stay in proportion to the rest of your theme — you don't need to pick them by hand, and they keep up automatically if you change your page or brand colours later. Set one yourself only if you want to break that link and fix its value instead; like any other variable on this page, it can be overridden in your custom CSS.

Variable
What it changes

--trn-surface-muted

Subtle tint on a card — callouts, empty states, hover fills, image placeholders

--trn-surface-strong

A stronger tint on a card — heavier fills and higher-contrast callouts

--trn-text-muted

Secondary text

--trn-text-subtle

The least prominent text — captions, helper copy

--trn-border

Standard borders and dividers

--trn-border-subtle

Faint borders and dividers, close to the background colour

--trn-button-bg-hover

Button background on hover

Component-level theming

A second layer of variables restyles one part of the widget without touching the base palette — useful when, say, you want squarer buttons but everything else unchanged. Each defaults to the base colour/corner setting above, so you only need to set the ones you want to differ:

Variable
What it changes
Defaults to

--trn-button-bg

Button background specifically (independent of the general brand colour)

--trn-brand

--trn-button-text

Button text colour specifically

--trn-on-brand

--trn-button-radius

Button corner rounding

--trn-radius-full (pill)

--trn-card-radius

Product/start-card corner rounding

--trn-radius-md

--trn-card-shadow

Drop shadow on cards, e.g. 0 2px 8px rgba(0, 0, 0, 0.08)

none

--trn-input-border

Form field border colour

--trn-border

Fonts and casing

Variable
What it changes

--trn-font-body

Font for all text, e.g. 'Inter', sans-serif. (--font-main is the legacy name for the same knob and is still honoured — the body font it holds flows through to --trn-font-body.)

--trn-font-heading

Headings only (defaults to --trn-font-body)

--trn-heading-text-transform

Set to uppercase to render headings in all caps; default none

--trn-button-text-transform

Set to uppercase to render button labels in all caps; default none

Renamed variables

Some variables on this page previously went by different names. If your custom CSS sets one of the old names, it still works — the value flows through to its replacement automatically — but use the new names in anything you write from now on:

Old name
New name

--trn-button-background-color

--trn-brand

--trn-button-text-color

--trn-on-brand

--trn-gray-1

--trn-button-bg-hover

--trn-gray-2

--trn-text-muted

--trn-gray-3

--trn-text-subtle

--trn-gray-4

--trn-border

--trn-gray-5

--trn-surface-strong

--trn-gray-6

--trn-border-subtle

--trn-gray-light

--trn-surface-muted

--trn-border-inner

--trn-radius-sm

--trn-border-outer

--trn-radius-md

--trn-border-full

--trn-radius-full

One difference worth knowing: the old grey scale was a set of fixed colours, while the new derived colours are computed live from your foreground and background — so they now stay in step when you change your base palette, instead of needing to be re-picked.

2. Custom CSS

Two habits make your CSS reliable:

  • Start every rule with #trn-app so it can only affect the widget, never the rest of your page.

  • Target the supported styling hooks below — they are stable across releases.

Recipes

Replacing the start-page card artwork

The cards on the start page ("trade in from your order history" / "registered products") ship with built-in illustrations. You can swap in your own artwork with custom CSS alone — no upload to Tern needed, just an image hosted at a public URL. If you're on Shopify, Content → Files in your Shopify admin gives you a CDN URL in two clicks.

Any image format the browser can load works: SVG, PNG, WebP, JPEG or GIF. SVG or a transparent PNG will look best against the card background.

To size the frame differently, set width and height on .trn-start-card__icon in the same rule.

A different image per card — the register / product-catalogue card carries a .trn-start-card--register modifier:

A different image per section — if you have both trade-ins and repairs enabled, the two start pages share the same cards. To vary the artwork by section, scope the rule with the card-row hooks .trn-start-cards--trade-in and .trn-start-cards--repairs:

Matching the theme colour — the built-in illustrations are drawn in your foreground colour. If you want your artwork tinted the same way, use it as a mask instead of a background: the image's own colours are ignored and its shape is filled with the current text colour (currentColor). This variant needs an image with transparency (SVG or transparent PNG/WebP — a JPEG won't work as a mask):

One thing to keep in mind: the image stays on your server, so if it's ever deleted or moved the cards will show an empty space until the URL is fixed.

Supported styling hooks (stable)

Naming pattern: hook names follow one grammar, so once you know it you can predict a name before you look it up. A block starts with the trn- prefix, e.g. .trn-product-card; a part inside it is the block name plus __element, e.g. .trn-product-card__image; a variant or state is the block name plus --modifier, e.g. .trn-button--outlined or .trn-option--selected. States are always modifiers, never bare classes — look for --selected / --open / --active, not .selected / .open / .active.

Finding the right hook: you don't have to work from this page alone. In the Tern admin, the CSS tab of the Copy Customisation screen has a built-in hook viewer — hover over any part of the preview and it highlights that element and the containers around it, listing the hooks on each, so you can see exactly what to target before you write the rule.

The hooks are grouped in the order your customers meet them — the path through the widget first, then the pieces that appear on every page. Each area separates layout wrappers — structural containers you'd target for spacing, width or positioning — from components — the visible pieces you'd restyle. Every hook has its own entry; simple ones list their parts inline, and anything richer gets a small table breaking its parts down by kind: Element — a __ part inside it, Variant — a -- kind it comes in, State — a -- condition it can enter.

The widget at a glance

The nesting here is indicative — it shows which hooks you'll find within which regions, not the exact markup (extra wrappers between them can change; see What not to target). The class names themselves are the stable contract.

Start page

Layout wrappers

.trn-start-cards — the row holding the start-page cards

  • Variants: .trn-start-cards--trade-in / .trn-start-cards--repairs — which section's start page the row is on

Components

.trn-start-card — one start-page card

  • Elements: .trn-start-card__icon — the card's illustration

  • Variants: .trn-start-card--register — the registered-products card

Picking items

Layout wrappers

.trn-pick-your-items — the item-picker page

Kind
Hook
What it is

Variant

.trn-pick-your-items--orders

The order-history view

Variant

.trn-pick-your-items--catalog

The product-catalogue view

Variant

.trn-pick-your-items--repairs

The repairs view

.trn-card-grid — the grid a set of cards is laid out in (order history, registered products, repairs)

.trn-catalog — the register-a-product / product-catalogue browser

Components

.trn-product-card — a product card

Kind
Hook
What it is

Element

.trn-product-card__image

The product image

Element

.trn-product-card__info

The card's text area

Element

.trn-product-card__title

The product title

Element

.trn-product-card__price

The price area

Element

.trn-product-card__variant

The variant/option title

Element

.trn-product-card__date

The purchase date

Element

.trn-product-card__check

The selected checkmark badge

Element

.trn-product-card__unavailable-note

The "not eligible" note

Variant

.trn-product-card--placeholder

A loading skeleton card

Variant

.trn-product-card--prompt

The register-a-product / browse-more prompt cards

State

.trn-product-card--selected

While the card is selected

State

.trn-product-card--unavailable

When the item isn't eligible

.trn-carousel — the featured-products carousel

Kind
Hook
What it is

Element

.trn-carousel__title

Its heading

Element

.trn-carousel__nav

The prev/next arrow buttons

Variant

.trn-carousel__nav--prev

The previous arrow

Variant

.trn-carousel__nav--next

The next arrow

.trn-thumb — the square product/item thumbnail, wherever one appears (cards, cart rows, the summary sidebar)

.trn-category-card — the category browse cards

.trn-breadcrumbs — the catalogue breadcrumb trail

  • Elements: .trn-breadcrumbs__item — each crumb

.trn-search — the product search bar

  • Elements: .trn-search__suggestions — the dropdown panel; .trn-search__suggestion — each row in it

.trn-actions-bar — the selection counter / next-step bar under the item-picker grids

  • Elements: .trn-actions-bar__info — its text

Condition questions

Layout wrappers

.trn-option-group — a group of answer options

  • Elements: .trn-option-group__header — its heading

Components

.trn-questions — the condition-questions dialog (trade-ins and repairs)

Kind
Hook
What it is

Element

.trn-questions__progress

The step progress bar

Element

.trn-questions__progress-step

One step in the bar

Variant

.trn-questions--compact

A tighter presentation of the dialog

State

.trn-questions__progress-step--active

The current step

.trn-question — one question

.trn-option — an individual answer pill or variant swatch

  • Elements: .trn-option__check — the checkmark badge

  • States: .trn-option--selected

.trn-item-summary — the "your item" recap panel shown alongside the questions

Checkout steps

Layout wrappers

.trn-checkout — the two-column shell every checkout step and the outcome pages sit in

Kind
Hook
What it is

Variant

.trn-checkout--cart

The cart step

Variant

.trn-checkout--address

The contact-details step

Variant

.trn-checkout--shipping

The shipping step

Variant

.trn-checkout--confirmation

The confirmation step

Variant

.trn-checkout--outcome

The outcome pages

.trn-shipping, previously listed on the checkout shell, has been removed — it duplicated .trn-checkout on every step. Use .trn-checkout--shipping to reach the shipping step only.

.trn-cart-items, .trn-checkout-summary, .trn-summary-sidebar — the three checkout regions inside the shell

.trn-summary-list — the itemised list inside the order summary and the reward-choice cards

.trn-carrier-options — the shipping-options list

Components

.trn-checkout-item — a cart/confirmation line-item row

Kind
Hook
What it is

Element

.trn-checkout-item__name

The item name

Element

.trn-checkout-item__variant

The variant/option title

Element

.trn-checkout-item__price

The price

Element

.trn-checkout-item__actions

The row's actions area

.trn-summary-total — the total row beneath the summary list

.trn-reward-choice — the cash-or-product reward picker

  • Elements: .trn-reward-choice__option — each choice

  • States: .trn-reward-choice__option--selected — the chosen one

.trn-carrier-option — one row in the shipping-options list

  • States: .trn-carrier-option--selected — the chosen row

.trn-cart-badge — the wizard's cart button

  • Elements: .trn-cart-badge__count — the item-count bubble

.trn-panel — the bordered panel each block of wizard content sits in (cart, contact details, shipping, confirmation); also used by collapsible sections

Outcome pages

.trn-outcome — the block wrapping the "thank you" / "requested" / "rejected" outcome pages (inside the .trn-checkout--outcome shell)

Kind
Hook
What it is

Element

.trn-outcome__title

The icon + heading row

Element

.trn-outcome__reference

The trade-in reference row, on all three pages

Element

.trn-outcome__steps

The numbered next-steps list

Element

.trn-outcome__labels

The shipping-label downloads

Element

.trn-outcome__contact

The "contact us" text on the rejected page

History & trade-in details

Layout wrappers

.trn-products-list — the item list inside a history accordion entry

Components

.trn-history-header — the page header on the History and trade-in details pages

.trn-accordion — collapsible sections; each history entry is one

Kind
Hook
What it is

Element

.trn-accordion__header

The clickable header row

Element

.trn-accordion__content

The collapsible body

State

.trn-accordion--open

While expanded

.trn-item-row — an item row inside a history accordion entry or a details card

.trn-badge — the status badge on history/details pages

Kind
Hook
What it is

Variant

.trn-badge--success

Success statuses

Variant

.trn-badge--error

Error statuses

Variant

.trn-badge--warning

Waiting statuses

Variant

.trn-badge--info

In-progress statuses

.trn-details-card — the info cards on the confirmation, details and summary pages; one purpose variant per card

Kind
Hook
What it is

Element

.trn-details-card__header

Its title row

Variant

.trn-details-card--shipping

The shipping card

Variant

.trn-details-card--items

The items card

Variant

.trn-details-card--tracking

The tracking card

Variant

.trn-details-card--credit

The credit/reward card

Variant

.trn-details-card--exchange

The exchange card

Variant

.trn-details-card--service

The service-cost card

Variant

.trn-details-card--summary

The summary card

Variant

.trn-details-card--customer

The customer-details card

.trn-tracking — the return-tracking timeline

Kind
Hook
What it is

Element

.trn-tracking__event

One timeline entry

Element

.trn-tracking__status

The entry's status

Element

.trn-tracking__date

The entry's date

Element

.trn-tracking__description

The entry's description

.trn-tracking-number — the tracking-number row above the timeline

The remaining hooks aren't tied to one page — they appear throughout the widget.

Buttons & forms

.trn-button — buttons

Kind
Hook
What it is

Element

.trn-button__spinner

The in-button loading spinner

Variant

.trn-button--outlined

The secondary (outlined) style

Variant

.trn-button--sm

Small

Variant

.trn-button--bold

Bold label

.trn-input-group — form fields

.trn-checkbox — checkboxes

.trn-validation, .trn-validation-error — form validation messages

Money display

.trn-reward-value — what you get for an item, however it's expressed: a formatted money amount, or a text description for a non-monetary reward (e.g. "20% off")

  • Elements: .trn-reward-value__terms — the terms-and-conditions asterisk

.trn-amount — any formatted currency figure, wherever it appears (history credit totals, sidebar totals, item prices)

These two overlap by design: a monetary reward carries both classes at once (.trn-reward-value.trn-amount) — one selector styles all money, the other styles all rewards.

Dialogs

.trn-modal — dialogs

Kind
Hook
What it is

Element

.trn-modal__backdrop

The backdrop

Element

.trn-modal__card

The dialog box

Element

.trn-modal__title

The title

Element

.trn-modal__content

The content area

Element

.trn-modal__footer

The footer

Element

.trn-modal__close

The close button

Variant

.trn-modal--fixed

A dialog fixed to the viewport

Variant

.trn-modal--absolute

A dialog positioned within the page

Variant

.trn-modal__card--fit-content

A dialog sized to its content

Variant

.trn-modal__content--fit-content

A dialog sized to its content

Variant

.trn-modal--refund-questions

The questions dialog opened inside the refund widget

Use the variants when you want a rule to apply to only one kind of dialog.

Chrome & feedback

Frame

.trn-navbar — the widget's top navigation

  • Elements: .trn-navbar__inner — its inner wrapper; .trn-navbar__item — each link

.trn-footer — the widget's footer

.trn-wizard — the chrome around each wizard step (title, progress bar, back link)

Kind
Hook
What it is

Element

.trn-wizard__title

The step title

Element

.trn-wizard__progress

The progress-bar track

Element

.trn-wizard__progress-bar

The filled portion of the track

.trn-back-btn — the wizard's Back link

Feedback

.trn-alert — notification banners

Kind
Hook
What it is

Element

.trn-alert__icon

The severity icon

Element

.trn-alert__content

The message body

Variant

.trn-alert--info

Info severity

Variant

.trn-alert--success

Success severity

Variant

.trn-alert--warning

Warning severity

Variant

.trn-alert--error

Error severity

Variant

.trn-alert--fixed

Pinned to the viewport

State

.trn-alert--disabled

While disabled

.trn-info-box — inline info callouts

.trn-loading — the loading state

  • Elements: .trn-loading__spinner, .trn-loading__text

.trn-pagination-wrapper — pagination controls

  • States: the current page and disabled arrows are targetable as plain .active / .disabled classes within it

Refund widget dialog

.trn-refund-modal — the refund widget's popup (the "trade in" dialog embedded on a product page); the class sits on the backdrop

Kind
Hook
What it is

Element

.trn-refund-modal__content

The dialog box

Element

.trn-refund-modal__close

The close button

Element

.trn-refund-modal__body

The scrollable content area

This dialog's chrome renders outside #trn-app, so rules for it can't start with #trn-app — start them with .trn-refund-modal instead. Everything inside the body is the normal Returns Centre widget, so any rule targeting something in there starts with #trn-app as usual.

Text styles

.h1, .h2, .h3, .h4, .subtitle, .caption, .button-text, .strong.

What not to target

Alongside the styling hooks above you'll see lots of short, generated utility classes in the widget's HTML — things like mt-6, w-12, flex, uppercase. If you use Tailwind CSS yourself you'll recognise these; they are output of our build tooling, not a stable API. They can appear, disappear or move to different elements in any release, without notice.

The FilePond file-upload widget's filepond--* classes are third-party DOM and are not covered by this contract either.

Also avoid relying on the exact wrapper structure between supported elements (extra divs, element types) — it can change as we improve the widget.

Missing a hook? If there's something you want to restyle and no supported hook reaches it, tell us at support@tern.eco — adding a stable class for you is quick and safe, and much better than either of us relying on generated names. Check the component-level theming table too: a lot of what used to need a hook is now a one-line variable instead.

3. Tips

  • The widget's sizing is pixel-based on purpose — it does not use rem units, so it will not be affected by your theme's root font-size. We recommend px units in your custom CSS for the same predictability.

  • The Copy Customisation screen previews your CSS exactly the way the live storefront applies it — check there before publishing.

  • Keep a copy of your custom CSS in your own records; it's the quickest way to review what you've changed if you redesign later.

Last updated