Triiiceratops Theming

Theming and Styling

Style Triiiceratops with vanilla-CSS design tokens: three approaches, from swapping a built-in theme to overriding individual tokens.

Triiiceratops ships a small set of vanilla-CSS design tokens. There are three ways to style the viewer, from easiest to most granular:

  1. Pick a built-in theme (theme prop).

  2. Override tokens with the themeConfig prop (typed, friendly names).

  3. Set the underlying CSS variables directly on the host element.

These aren't exclusive tiers you have to climb in order — you can override just one piece of a built-in theme (e.g. tweak primary via themeConfig while keeping dark's other tokens as-is), or skip built-in themes entirely and build a fully custom theme from scratch by setting the CSS variables yourself.

These three are the whole styling surface. The viewer's shadow-DOM internals are not reachable from the outside: there is no ::part() surface, no way to inject a consumer stylesheet into the shadow root, and no light-DOM styling hook for internal elements. Everything about the host element — layout, size, borders, and any CSS that treats it as a box in your page — is yours as usual.

Every host takes the same two inputs, theme and themeConfig — as props in React, Vue, and Svelte, and as an attribute plus a property on the custom element. Pick your stack's tab in the examples below.

All three compose, but they do not have equal precedence. From lowest to highest: OS-aware default tokens, CSS variables inherited from the host/page, an explicit built-in theme, then themeConfig inline styles. If you set theme, that selected theme wins over CSS variables set outside the viewer; use themeConfig for overrides that must win over an explicit built-in theme.

1. Built-in Themes

Four themes ship with the viewer: two light (light, teal) and two dark (dark, dracula). Theme names are case-sensitive. Set no theme and the viewer paints light: which scheme a reader sees is the page's decision rather than the component's, so follow their own preference where you want that — theme={prefersDark ? 'dark' : 'light'}. A viewer can also inherit CSS variables from the host page.

<triiiceratops-viewer manifest-id="..." theme="dark"></triiiceratops-viewer>

2. Custom Theme Configuration

Override individual tokens with themeConfig — no CSS required. Colors accept Hex (#3b82f6), RGB (rgb(59, 130, 246)), or OKLCH (oklch(60% 0.25 250)); the viewer applies the value exactly as you wrote it.

Palette

Keyword

Description

CSS Variable

primary

Primary brand color (buttons, active states)

--tri-color-primary

primaryContent

Text color on a primary background

--tri-color-primary-content

neutral

Neutral color (tooltips, active menu items)

--tri-color-neutral

neutralContent

Text color on a neutral background

--tri-color-neutral-content

success

Success state

--tri-color-success

successContent

Text color on a success background

--tri-color-success-content

warning

Warning state

--tri-color-warning

warningContent

Text color on a warning background

--tri-color-warning-content

error

Error state

--tri-color-error

errorContent

Text color on an error background

--tri-color-error-content

Surfaces

Surfaces are named by the region they paint. panelBg is the default for every panel (including plugin panels); galleryBg and inputBg follow viewerBg by default.

Keyword

Description

CSS Variable

viewerBg

Main viewer/canvas background

--tri-viewer-bg

toolbarBg

Toolbar + canvas-nav controls background

--tri-toolbar-bg

panelBg

Default background for all side panels

--tri-panel-bg

galleryBg

Thumbnail gallery background

--tri-gallery-bg

inputBg

Form input/control surface

--tri-input-bg

surfaceBorder

Borders and dividers

--tri-surface-border

Content (foreground)

content is the global text/icon color. The per-region tokens below inherit from it and let you retint text in one region without touching the rest.

Keyword

Description

CSS Variable

content

Global default text/icon color

--tri-content

panelContent

Text color inside panels

--tri-panel-content

toolbarContent

Text color inside the toolbar

--tri-toolbar-content

viewerContent

Text color over the viewer surface

--tri-viewer-content

galleryContent

Text color inside the gallery

--tri-gallery-content

Per-panel overrides

Each panel's background and text default to panelBg / panelContent. Override one panel without affecting the others. Setting panelBg: 'green' tints every panel; additionally setting metadataPanelBg: 'white' overrides just the metadata panel.

Keyword (…Bg / …Content)

Panel

CSS Variable (…-bg / …-content)

metadataPanel…

Information / metadata panel

--tri-metadata-panel-…

annotationsPanel…

Annotations panel

--tri-annotations-panel-…

searchPanel…

Search panel

--tri-search-panel-…

structuresPanel…

Table-of-contents panel

--tri-structures-panel-…

collectionPanel…

Collection panel

--tri-collection-panel-…

Plugin panels have no per-panel token of their own: they take panelBg / panelContent like every other panel. First-party plugin CSS reads the public --tri-* tokens above (--tri-input-bg, --tri-surface-border, --tri-radius-panels, and the palette), so retinting those retints the plugin panels with them. A plugin that defines its own custom property can be fed through the cssVars escape hatch.

Border radius

The top-level trio sets the defaults; the per-region overrides inherit from them, so you can keep everything consistent or fine-tune one region.

Keyword

Description

Inherits

CSS Variable

radiusBox

Large containers (cards, panels, popovers)

--tri-radius-box

radiusButtons

Buttons, inputs, and button groups

--tri-radius-buttons

radiusSelector

Small selectors (checkboxes, badges)

--tri-radius-selector

radiusToolbar

Toolbar corners

radiusButtons

--tri-radius-toolbar

radiusPanels

Panel corners

radiusBox

--tri-radius-panels

radiusControls

Canvas-nav controls pill

radiusButtons

--tri-radius-controls

radiusControlsButtons

The buttons inside the canvas-nav pill

radiusButtons

--tri-radius-controls-buttons

Want the classic pill? The canvas-nav controls inherit the button radius by default. For the fully-rounded capsule and circular buttons, set radiusControls: '9999px' and radiusControlsButtons: '9999px'.

Sizing & effects

Keyword

Description

CSS Variable

Example

sizeField

Base padding/size for inputs

--tri-size-field

0.25rem

sizeSelector

Base padding/size for selectors

--tri-size-selector

0.25rem

border

Border width

--tri-border

1px

depth

Drop shadows (1 = on, 0 = off)

--tri-depth

1

colorScheme

Browser UI hint (light/dark)

color-scheme

light

Complete public token reference

Every token below is part of the semver-governed public customization surface. Variables outside the --tri-* namespace are internal implementation details with no stability guarantee — --ui-* layout plumbing and component-local --btn-* / --range-* variables among them — with two exceptions, the typeface properties documented in Typefaces below. Set a token either by its themeConfig key or by writing the raw CSS variable; tokens marked — (raw only) have no typed key and must be set through cssVars or plain CSS. The table is core’s own tokens. A plugin may declare further --tri-* properties of its own, governed by that plugin’s version and documented on its page: the annotation editor’s drawing layer is the first-party example.

Palette

CSS variablethemeConfig key
--tri-color-primaryprimary
--tri-color-primary-contentprimaryContent
--tri-color-primary-text— (raw only)
--tri-color-neutralneutral
--tri-color-neutral-contentneutralContent
--tri-color-successsuccess
--tri-color-success-contentsuccessContent
--tri-color-warningwarning
--tri-color-warning-contentwarningContent
--tri-color-errorerror
--tri-color-error-contenterrorContent

Surfaces

CSS variablethemeConfig key
--tri-viewer-bgviewerBg
--tri-toolbar-bgtoolbarBg
--tri-panel-bgpanelBg
--tri-gallery-bggalleryBg
--tri-input-bginputBg
--tri-surface-bordersurfaceBorder

Content / foreground

CSS variablethemeConfig key
--tri-contentcontent
--tri-panel-contentpanelContent
--tri-toolbar-contenttoolbarContent
--tri-viewer-contentviewerContent
--tri-gallery-contentgalleryContent

Per-panel overrides

CSS variablethemeConfig key
--tri-metadata-panel-bgmetadataPanelBg
--tri-metadata-panel-contentmetadataPanelContent
--tri-annotations-panel-bgannotationsPanelBg
--tri-annotations-panel-contentannotationsPanelContent
--tri-search-panel-bgsearchPanelBg
--tri-search-panel-contentsearchPanelContent
--tri-structures-panel-bgstructuresPanelBg
--tri-structures-panel-contentstructuresPanelContent
--tri-collection-panel-bgcollectionPanelBg
--tri-collection-panel-contentcollectionPanelContent

Border radius

CSS variablethemeConfig key
--tri-radius-selectorradiusSelector
--tri-radius-buttonsradiusButtons
--tri-radius-boxradiusBox
--tri-radius-toolbarradiusToolbar
--tri-radius-panelsradiusPanels
--tri-radius-controlsradiusControls
--tri-radius-controls-buttonsradiusControlsButtons

Sizing

CSS variablethemeConfig key
--tri-size-selectorsizeSelector
--tri-size-fieldsizeField

Border / effects

CSS variablethemeConfig key
--tri-borderborder
--tri-depthdepth

Typefaces

The viewer ships no font files and downloads none. It names two custom properties and falls back to the reader's system faces, so out of the box it is set in whatever your platform's UI sans and mono are. These two are public API alongside the --tri-* tokens above, despite being outside that namespace: they are the whole mechanism for matching the viewer to your own site's type.

CSS variable

Applies to

Fallback when unset

--default-font-family

all text in the viewer

ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'

--default-mono-font-family

code, kbd, samp, pre

ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace

Neither has a themeConfig key: a typeface is a property of the page the viewer sits in rather than of a theme, and the viewer is meant to inherit it. Set them wherever they will reach the viewer — on :root for a whole page, or on the viewer's own element to give it its own type:

:root {
    --default-font-family: 'Source Serif 4', Georgia, serif;
    --default-mono-font-family: 'Source Code Pro', ui-monospace, monospace;
}

Both take a full font stack, not a single family, and it is worth writing the fallbacks out: the viewer cannot load a face for you, so a stack naming only a webfont your page has not fetched renders in the browser's last-resort default. Loading the face — an @font-face rule, a <link>, whatever your site already does — remains yours.

Example Usage

As an attribute, JSON-encoded:

<triiiceratops-viewer
    manifest-id="..."
    theme="light"
    theme-config='{"primary":"#ff0000","panelBg":"#fafafa","radiusBox":"0px"}'
></triiiceratops-viewer>

Or as a property, from JavaScript:

<triiiceratops-viewer manifest-id="..."></triiiceratops-viewer>

<script>
    const viewer = document.querySelector('triiiceratops-viewer');
    viewer.theme = 'light';
    viewer.themeConfig = {
        primary: '#3b82f6',
        toolbarBg: '#1f2937',
        panelBg: '#f3f4f6',
        metadataPanelBg: '#ffffff',
        content: '#1f2937',
        radiusBox: '0.75rem',
        border: '2px',
    };
</script>

Assign a new themeConfig object when updating from JavaScript. Mutating a nested property on the existing object does not notify the custom element.

Raw CSS variables

For tokens without a typed key — --tri-color-primary-text, or a custom property a plugin reads — use the cssVars escape hatch. Keys are CSS variable names without the leading --, and the viewer does not check them against its own token list, so a name nothing reads simply has no effect:

viewer.themeConfig = {
    panelBg: 'oklch(20% 0.02 277)',
    cssVars: {
        'tri-color-primary-text': '#c7d2fe',
        'my-plugin-accent': '#0b1020',
    },
};

3. Styling with CSS Variables

Because the tokens are plain custom properties that inherit through the shadow boundary, you can theme the viewer from your own CSS by targeting the host element. This is equivalent to themeConfig only when no explicit theme is set; if a built-in theme is selected, the theme's token values win over host CSS variables.

triiiceratops-viewer {
    --tri-color-primary: oklch(65% 0.25 260);
    --tri-panel-bg: #1e1e2e;
    --tri-metadata-panel-bg: #181825; /* override one panel */
    --tri-radius-box: 0;
    --tri-radius-controls: 9999px; /* keep the controls pill rounded */
}

A selected built-in theme wins over CSS variables you set this way; themeConfig (inline styles) wins over everything. In Svelte/light-DOM usage, you can also switch among built-in themes by setting data-theme on an ancestor when you leave the viewer's theme prop unset:

<div data-theme="dracula">
    <TriiiceratopsViewer manifestId="..." />
</div>

For the web component, prefer the theme attribute/property for built-in themes:

<triiiceratops-viewer manifest-id="..." theme="dracula"></triiiceratops-viewer>