Skip to content

Token reference

The --theme-* contract as the base theme emits it, beside the same token in the two custom themes the component pages are shot on. Where a row repeats a value, that theme had no reason to diverge — a custom theme is expected to redeclare the whole contract, not to change every value in it.

Read this next to a component page

Each component page lists the subset of these it actually reads.

Colour

What the set is painted with. -ink is body text, -surface is the page, -border-strong is a rule that carries structure rather than merely separating.

Every colour token here falls back to its Bootstrap equivalent before it falls back to a literal — var(--theme-color-primary, var(--bs-primary, #0d6efd)). So a theme that declares only part of the contract still gets its own colours for the rest, rather than stock Bootstrap blue: the token wins if set, the theme's --bs-* wins next, and the literal is reached only when neither exists. --theme-color-primary-ink is the exception — it is a computed contrast colour and Bootstrap emits no variable for it, so it keeps a literal.

Token Base Light Dark
--theme-color-primary #0d6efd #8a6a4f #ffb443
--theme-color-primary-ink #fff #fff #050505
--theme-color-secondary #6c757d #6e6b66 #b8b8b8
--theme-color-ink #212529 #1c1b19 #f5f5f5
--theme-color-ink-muted rgba(33, 37, 41, 0.75) #6e6b66 #b8b8b8
--theme-color-surface #fff #fbfaf8 #050505
--theme-color-surface-subtle #f8f9fa #f4f1ec #0a0a0a
--theme-color-surface-inverse #212529 #1c1b19 #f5f5f5
--theme-color-border #dee2e6 #e8e5e0 #222
--theme-color-border-strong #dee2e6 #e8e5e0 #333

Type

One ramp for the whole set. Sizes may be fluid clamp() or fixed — components never assume either.

Token Base Light Dark
--theme-font-heading system-ui, -apple-system, Segoe UI, roboto, H… Figtree, system-ui, -apple-system, Segoe UI, … Manrope, system-ui, -apple-system, Segoe UI, …
--theme-font-body system-ui, -apple-system, Segoe UI, roboto, H… Figtree, system-ui, -apple-system, Segoe UI, … Manrope, system-ui, -apple-system, Segoe UI, …
--theme-font-mono SFMono-Regular, Menlo, Monaco, Consolas, Liberation… SFMono-Regular, Menlo, Monaco, Consolas, Liberation… JetBrains Mono, sfmono-regular, menlo, monaco…
--theme-font-size-sm 0.875rem 0.8125rem 0.8125rem
--theme-font-size-base 1rem clamp(1rem, 0.96rem + 0.14vw, 1.0625rem) clamp(1rem, 0.96rem + 0.14vw, 1.0625rem)
--theme-font-size-lg 1.25rem clamp(1.0625rem, 0.99rem + 0.26vw, 1.1875rem) clamp(1.0625rem, 0.99rem + 0.26vw, 1.1875rem)
--theme-font-size-h6 1rem 0.9375rem 0.9375rem
--theme-font-size-h5 1.25rem 1.0625rem 1.0625rem
--theme-font-size-h4 1.5rem clamp(1.125rem, 1.078rem + 0.19vw, 1.25rem) clamp(1.125rem, 1.06rem + 0.28vw, 1.3125rem)
--theme-font-size-h3 1.75rem clamp(1.3125rem, 1.242rem + 0.29vw, 1.5rem) clamp(1.375rem, 1.24rem + 0.58vw, 1.75rem)
--theme-font-size-h2 2rem clamp(1.625rem, 1.393rem + 0.95vw, 2.25rem) clamp(1.875rem, 1.46rem + 1.72vw, 3rem)
--theme-font-size-h1 2.5rem clamp(2rem, 1.63rem + 1.52vw, 3rem) clamp(2.375rem, 1.62rem + 3.1vw, 4.25rem)
--theme-font-size-display 3.5rem clamp(2.375rem, 1.863rem + 2.1vw, 3.75rem) clamp(2.75rem, 1.55rem + 4.9vw, 6rem)
--theme-leading-tight 1.2 1.12 1.04
--theme-leading-heading 1.2 1.22 1.2
--theme-leading-normal 1.5 1.75 1.55
--theme-leading-relaxed 2 1.9 1.72
--theme-tracking-tight 0 -0.012em -0.03em
--theme-tracking-eyebrow 0 0.01em 0.14em
--theme-heading-weight 500 500 800
--theme-eyebrow-case none none uppercase
--theme-measure 44rem 38rem 44rem

Space

--theme-space-section is the band rhythm and does more for the out-of-the-box feel than any colour here.

Token Base Light Dark
--theme-spacer 1rem 1rem 1rem
--theme-spacer-1 0.25rem 0.25rem 0.25rem
--theme-spacer-2 0.5rem 0.5rem 0.5rem
--theme-spacer-3 1rem 1rem 1rem
--theme-spacer-4 1.5rem 1.5rem 1.5rem
--theme-spacer-5 3rem 3rem 3rem
--theme-space-section 3rem clamp(4.5rem, 9vw, 9rem) clamp(3.5rem, 7vw, 7rem)
--theme-space-gutter 1.5rem 0rem 0rem

Container geometry

The split hero aligns its text column with the page's centered container by reproducing that container's max-width per breakpoint. Each token falls back to Bootstrap's stock $container-max-widths value, so a stock-Bootstrap theme declares nothing. A theme that customizes those widths — or any non-Bootstrap theme — must declare all five, or the full-bleed hero's content drifts out of step with every other section on the page.

Token Breakpoint Fallback
--theme-container-sm ≥576px 540px
--theme-container-md ≥768px 720px
--theme-container-lg ≥992px 960px
--theme-container-xl ≥1200px 1140px
--theme-container-xxl ≥1400px 1320px

Shape

One radius decision, spent everywhere.

Token Base Light Dark
--theme-radius 0.375rem 0.25rem 0.25rem
--theme-radius-lg 0.5rem 0.375rem 0.375rem
--theme-radius-pill 50rem 50rem 0.25rem

Elevation

A flat theme sets both to none; they exist so a warmer theme can opt back in without touching a component.

Token Base Light Dark
--theme-shadow-sm 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) none none
--theme-shadow-md 0 0.5rem 1rem rgba(0, 0, 0, 0.15) none none

Motion

Every component transition reads these, so one change retimes the whole set.

Token Base Light Dark
--theme-duration 0.2s 220ms 220ms
--theme-ease ease-in-out cubic-bezier(0.22, 0.61, 0.36, 1) cubic-bezier(0.22, 0.61, 0.36, 1)

Declared by the bridge

These are not part of the core contract — the shared Bootstrap bridge declares them so bootstrap_components and the carousel have a documented extension point. Override them the same way.

Token Purpose
--theme-accordion-btn-active-icon-color Accordion chevron colour while the item is open.
--theme-accordion-btn-hover-bg Accordion header hover — Bootstrap ships no hover state for the header at all.
--theme-accordion-btn-hover-color Accordion header hover — heading text colour.
--theme-accordion-btn-hover-icon-color Accordion header hover — chevron colour.
--theme-accordion-btn-icon-color Accordion chevron colour at rest. Defaults to currentcolor.
--theme-carousel-caption-color-dark Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-caption-scrim Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-color Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-color-dark Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-icon-size Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-opacity Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-opacity-active Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-control-width Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-indicator-padding-block Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-carousel-indicator-padding-inline Carousel chrome — scrim, control colour, opacity, hit padding.
--theme-close-btn-padding Sized in em so it scales with .btn-close's glyph, not a spacer.
--theme-color-focus Focus-ring colour; defaults to the accent.
--theme-shadow-sm-2 Second shadow layer for stacked card elevation.
--theme-touch-target-min WCAG 2.5.5 minimum hit area. Do not lower it.

--theme-touch-target-min is an accessibility floor

Buttons buy their 44px target through padding rather than a min-height rule, so a theme that resizes buttons keeps the target by default. Lowering this token silently drops the set below WCAG 2.5.5.

Component tokens

Every component that declares its own --<component>-* tokens lists them here, alongside the subset of the --theme-* contract above that it actually reads. See the component's own Theming tab for the short version of what to override in context.

Hero Banner

The diagram below places the ones tied to a specific region; the rest — spacing between regions, breakpoint-driven, or shared across layouts — are called out underneath it.

--hero-eyebrow-color / --hero-eyebrow-color-light
CTA --hero-banner-cta-radius ↕ --hero-content-pad-bottom
↕ --hero-split-media-min-height

--hero-split-content-width how wide the text column is, which the arrows line up with · --hero-split-content-gap space between the two columns · --hero-split-container-inset outer margin each side, recalculated at every Bootstrap breakpoint from --theme-container-* (see below) · --hero-carousel-control-width how far the prev/next arrows sit from the edge · --hero-nav-* the round prev/next buttons' fill and border, at rest and on hover, for both carousel engines · --swiper-pagination-* the dots below a Swiper carousel · --hero-controls-bg background behind a video slide's audio controls, unset (transparent) by default

Token Default
--hero-eyebrow-color var(--bs-primary, #0a58ca)
--hero-eyebrow-color-light #fff
--hero-content-pad-bottom clamp(1.5rem, 0.5rem + 2vw, 2.5rem)
--hero-banner-cta-radius var(--theme-radius, 0)
--hero-controls-bg (unset — transparent until a theme sets it)
--hero-carousel-control-width 15%
--hero-nav-bg rgb(255 255 255 / 8%) ( rgb(0 0 0 / 5%) on a light banner)
--hero-nav-border rgb(255 255 255 / 65%) ( rgb(0 0 0 / 50%) on a light banner)
--hero-nav-bg-hover rgb(255 255 255 / 18%) ( rgb(0 0 0 / 10%) on a light banner)
--hero-nav-border-hover #fff ( rgb(0 0 0 / 80%) on a light banner)
--hero-gradient-horizontal-angle 270deg
--hero-gradient-horizontal-color #000
--hero-gradient-horizontal-opacity 0.55
--hero-gradient-vertical linear-gradient(180deg, rgb(0 0 0 / 0%) 0%, rgb(0 0 0 …
--hero-gradient-vertical-opacity 1
--hero-indicator-hit-padding 8px
--hero-preloader-size 60px
--hero-split-container-inset 0.75rem below the sm breakpoint; see note above
--hero-split-content-gap 2.5rem
--hero-split-content-width 40%
--hero-split-control-inline follows --hero-split-content-width
--hero-split-media-min-height 240px
--hero-video-max-height 56.25cqw
--hero-video-max-width 177.78cqh
--swiper-pagination-bullet-border-radius 4px
--swiper-pagination-bullet-height 8px
--swiper-pagination-bullet-horizontal-gap 5px
--swiper-pagination-bullet-inactive-color #fff
--swiper-pagination-bullet-inactive-opacity 0.5
--swiper-pagination-bullet-width 8px
--swiper-pagination-color #fff
--swiper-theme-color var(--bs-light)

Layout-specific min-heights (--hero-min-height-mobile / -desktop) and suggested image aspect ratios per layout are covered in Retheme a Hero Banner, next to the rest of that layout-level guidance.

Theme tokens it reads

Change either of these and this component follows, along with everything else that reads them. This is the component's whole --theme-* surface — no other --theme-* token affects Hero Banner's own rendering.

Token Bootstrap default Custom theme
--theme-font-size-sm 0.875rem 0.8125rem
--theme-radius (not set by default — the CTA's radius is pinned to 0 directly instead, see Retheme a Hero Banner) 0.75rem

Split layout also reads --theme-container-sm through --theme-container-xxl at each breakpoint, to keep its content column aligned with the rest of the page's containers — see Container geometry above. The live builder's Theme toggle also sets --theme-container-lg: 1100px for Custom theme, but that one's too subtle to see at iframe scale — it nudges Split's content-column inset, not anything with a visible edge in the demo.

The live builder's placeholder image also changes color between the two Theme options — that's --theme-color-primary, but it's not a Hero Banner token. It's read by the shared media-placeholder.css used across every "no image selected" state in IXM Blocks, not by hero_banner.css itself; the demo loads that shared file too, so toggling Theme there shows #10564f — the exact brand colour the retheme walkthrough picks — standing in for Bootstrap's default blue, the same as it would on any other component's placeholder.