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:
Theme settings — colours, fonts and corner rounding that restyle the whole widget consistently. No CSS knowledge needed. Start here.
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-6orflex. 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:
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.
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.
--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.
--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.
--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.
--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.
--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:
--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
--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:
--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-appso 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 illustrationVariants:
.trn-start-card--register— the registered-products card
Picking items
Layout wrappers
.trn-pick-your-items — the item-picker page
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
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
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)
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 badgeStates:
.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
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-checkouton every step. Use.trn-checkout--shippingto 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
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 choiceStates:
.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)
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
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
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
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
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
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
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)
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
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/.disabledclasses 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
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
remunits, so it will not be affected by your theme's rootfont-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