Compass Web SDK: Theming Reference
Every SDK-rendered Experience shares one theming contract. Set your brand once and all three pick it up:
<arc-compass-recommendations-carousel>and<arc-compass-recommendations-list>— see Recommendations Components.<arc-compass-catchup-card>— see Catch Up Card.
Each Experience renders inside a shadow root: your page’s CSS cannot reach its internals, and its internals are not part of the API. You theme it through two public surfaces only:
- CSS custom properties (
--arc-compass-*), which cascade through the shadow boundary. Set them on the tag, a wrapping selector, or:root. ::part()hooks on named elements, for restyling an element outright. Each component page lists its own part names.
Everything else — the markup between the parts, class names, and internal custom
properties (anything prefixed --_) — is internal and can change in any release.
Tokens
One table for all three Experiences. The Applies to column says where a token has a visible effect; setting a token on an Experience that does not use it is harmless, so a single brand block can target all three.
| Property | Default | What it controls | Applies to |
|---|---|---|---|
--arc-compass-surface | Canvas (system) | Background where Compass owns the surface — the full-screen Catch Up takeover. Must be opaque. | Catch Up Card |
--arc-compass-on-surface | currentColor | Ink on the surface: text, plus the neutral ramp (muted text, hairlines, subtle fills) derived from it. | Catch Up Card |
--arc-compass-accent | currentColor | Primary accent. Colors the kicker above each recommendation headline, and the Catch Up Card’s links, active states, and filled controls (“Catch me up,” “I’m caught up”). | All three |
--arc-compass-on-accent | #fff | Foreground on an accent fill (button text and icons). Set it when your accent is light. | Catch Up Card |
--arc-compass-accent-secondary | the primary accent | Premium badge on recommendation cards, including the Catch Up Card’s “You might also be interested in” list. Deprecated — see The secondary accent. | All three |
--arc-compass-font-family | inherited page font | Primary typeface — headlines and running text. | All three |
--arc-compass-font-family-secondary | the primary typeface | Secondary typeface — kickers, badges, labels, and meta. | All three |
--arc-compass-radius | .5rem | Corner rounding — cards, images, and buttons. See Corner radius. | All three |
--arc-compass-card-min-width | 220px | Minimum card width in the recommendations grid — the one density knob. See Sizing the cards with one value. | Recommendations |
The recommendations Experiences are transparent and draw text in your page’s own
color, so they do not read the surface/on-surface pair. The Catch Up Card is
the only Experience that paints a surface of its own.
Zero-config appearance
With no tokens set, Experiences render “native”: text follows your page’s color, both accents fall back to that same color, and running text inherits your page’s font, so an unthemed component is monochrome but never clashes. The one exception is the Catch Up Card’s typography: until you set the font tokens, its headlines use Georgia and its intro line uses Inter, its built-in look.
The SDK never ships or @font-faces a typeface. Load your fonts as you already
do and point the tokens at them. Set only --arc-compass-font-family and the
secondary roles use that one face too.
Copy-paste brand block
Set the tokens once on :root and every Experience on the page follows. Fill in
your own values:
:root { /* Typefaces — load them yourself; the SDK never ships a font. */ --arc-compass-font-family: "Publico", Georgia, serif; --arc-compass-font-family-secondary: "Franklin", Arial, sans-serif;
/* Accent: recommendation kickers and the Catch Up Card's controls. */ --arc-compass-accent: #b00020; --arc-compass-on-accent: #ffffff; /* text on an accent fill */
/* Surface pair: the Catch Up Card's full-screen takeover. Opaque. */ --arc-compass-surface: #ffffff; --arc-compass-on-surface: #1a1a1a;
/* Shape and density. */ --arc-compass-radius: 8px; --arc-compass-card-min-width: 240px;}Leave --arc-compass-accent-secondary out of a new theme: the premium badge
takes the primary accent.
Light and dark recipe
Compass’s colors come from your tokens, not the reader’s OS. Two pairs define
the whole palette: surface/on-surface set the background and ink, and every
neutral (muted text, hairlines, subtle fills) is derived from them;
accent/on-accent do the same for filled controls. To support a dark edition,
override those four for whatever selector marks it, and set color-scheme so
native browser chrome (the takeover’s scrollbar) matches:
/* Light — the default edition. */:root { --arc-compass-surface: #ffffff; --arc-compass-on-surface: #1a1a1a; --arc-compass-accent: #b00020; --arc-compass-on-accent: #ffffff;}
/* Dark — scope to however your site marks its dark edition. */.night-edition { --arc-compass-surface: #14161c; /* opaque page background */ --arc-compass-on-surface: #eef1f6; /* light ink */ --arc-compass-accent: #f2b705; /* amber */ --arc-compass-on-accent: #14161c; /* dark text on amber, not white */}
.night-edition :is( arc-compass-recommendations-carousel, arc-compass-recommendations-list, arc-compass-catchup-card ) { color-scheme: dark;}To follow the reader’s OS setting instead of a class, put the dark block inside
@media (prefers-color-scheme: dark) { :root { … } }.
You do not need color-scheme, prefers-color-scheme, or system colors to
make Compass’s own UI dark — the badge, pills, hairlines, muted text, and
takeover all derive from the two pairs. In the recommendations Experiences, the
dark edition comes from your page: the cards are transparent and draw text in
your page’s color, so only the accent needs a dark-friendly value.
Corner radius
--arc-compass-radius is the base every rounded surface derives from, so one
brand radius rounds the recommendation cards and the Catch Up Card alike. Set it
to a single CSS length with a unit. Anything else fails silently: a unitless
number (8) is not a length, so every corner goes square, and a multi-value
radius (8px 16px) rounds only the buttons. For square corners throughout, write
0px.
Buttons take the token as-is, so a pill-sized value (999px) gives you pill
buttons. Containers — frames, images, rows — follow the token up to 1rem and
hold there, so they stay rectangles however large the value. Pills, dots, and the
round carousel arrows are shapes rather than rounding and do not follow it. Rely
on the token moving every Experience’s rounding together, not on a given surface
getting a given fraction of it — the proportions can be retuned in any release.
The secondary accent
--arc-compass-accent-secondary colors only the premium badge, on the
recommendation cards and in the Catch Up Card’s “You might also be interested in”
list. It is deprecated: when unset, the badge takes --arc-compass-accent,
so you can drop it from your theme. A site that already sets both accents renders
unchanged, and the token keeps working until a future major version removes it.
What the shadow boundary does and does not protect
Selectors do not cross a shadow boundary. A global reset (* { margin: 0 }),
an aggressive framework rule, an !important on a class: none of them can match
anything inside an Experience. You do not need to scope your CSS away from the
Experiences, and they do not need !important to defend against your page.
Inheritance does cross it. Inherited properties set on an ancestor flow into
the shadow tree, so that is the only real vector. The Experiences reset the
inherited properties that can distort a layout rather than restyle it:
line-height, letter-spacing, word-spacing, text-transform,
text-indent, white-space, text-align, direction, and visibility.
font-family and color are deliberately not reset. Inheriting them is the
zero-config story — an Experience should look like the page it sits in — and
neither can break geometry. The practical consequence: if your page sets
text-transform: uppercase on body, your own text is uppercase and the
Experience’s is not. Use the tokens to theme it.
Styling internals with ::part()
Tokens change values Compass anticipated. When you need to restyle an element outright — a different thumbnail aspect ratio, your own type scale — use the part hooks each component page lists:
Part names are versioned public surface: they will not be removed or moved to a different element within a major version.
Two rules apply to every Experience:
::part()selects the named element and nothing below it.::part(card) imgmatches nothing — style::part(thumbnail)instead. Every element you can restyle has its own name; if something you need is not in a part table, it is not stylable.- A
::part()declaration beats the Experience’s own rules, so stick to visual properties. Layout properties such asdisplayandpositionon a part can break the component — each component page notes the parts where this matters.
Setting tokens and parts from Tailwind
Tokens and parts are plain CSS, so they work whatever your styling stack is —
you are setting a custom property and matching a ::part() selector, not
reaching for a component API. Two ways to do it from Tailwind:
A stylesheet block (clearest for ::part() rules), colocated with the rest
of your CSS:
.rec-rail::part(card) { @apply rounded-lg border border-gray-200 bg-white;}.rec-rail::part(headline) { @apply text-base font-bold;}Arbitrary variants, straight on the tag, when you would rather stay in
markup. The tokens are a class; the parts need the [&::part(...)] escape hatch
because Tailwind has no built-in part variant:
<arc-compass-recommendations-list class="[--arc-compass-accent:theme(colors.red.600)] [&::part(card)]:rounded-lg [&::part(card)]:border [&::part(headline)]:font-bold"></arc-compass-recommendations-list>Either reaches the shadow tree — a ::part() rule is not blocked by the boundary
the way a descendant selector is. Utility resets do not leak in either (see
What the shadow boundary does and does not protect),
so you never need to scope Tailwind’s preflight away from the element.
See also
- Compass Web SDK: Recommendations Components — attributes, card sizing, and part names for the carousel and list.
- Compass Web SDK: Catch Up Card — attributes, events, and part names for the Catch Up Card.
- Compass Web SDK: Integration Guide — install, initialize, consent, and identity (required setup).