Host-page variables: --forumulate-host-* and the floatRoom contract
Every reader page we serve publishes its resolved brand as eight CSS custom properties on :root, so a widget that is not ours — a chat bubble, a consent banner, a referral card, any product's embed — can dress itself in the page's brand without knowing our internal token names (which change when we refactor). The names are a contract; the internal ones are not.
Variable | What it is | Unset theme value (light / dark) |
|---|---|---|
| The brand colour ( |
|
| Readable text on an accent fill (near-white or near-black) |
|
| The page colour ( |
|
| Body text ( |
|
| Rules and borders ( | 16% ink |
| Corner radius ( |
|
| The body font stack the page paints with | the system stack |
| A complete |
|
The older names still work. These variables first shipped as --fd-* (--fd-accent, --fd-accent-ink, … --fd-focus-ring). Every page still publishes those too, with the same values, so a widget built against them needs no change. Read the --forumulate-host-* names in anything new.
How they are set:
Server-rendered, no flash. The values are literals from the theme the page resolves (space theme over site theme over brand file, see Theme your site), written in the same
<style>as the rest of the theme. A widget that readsgetComputedStyle(document.documentElement)on its first frame already sees the brand.Dark mode follows the page: an OS preference the page does not override, or an explicit
<html data-theme="dark">.--forumulate-host-focus-ringis never absent and never invisible. It is set even on a page whose theme says nothing (the default is a 2px ring in the accent). An owner'scomponents.focus.coloris used as given; otherwise the accent when it reaches 3:1 against the page colour (WCAG 1.4.11), otherwise the page's ink. A theme cannot turn it off: the width floor is 1px. Our own focus styles draw with it, so a widget that uses it matches ours.
The website SDK reads them from your page
The same names work the other way round. If your page publishes them — by hand, or because your design system does — every @forumulate/embed element and mount function fills accent, radius and font from --forumulate-host-accent, --forumulate-host-radius and --forumulate-host-font when you leave those unset:
:root {
--forumulate-host-accent: #0f766e;
--forumulate-host-radius: 12px;
--forumulate-host-font: 'Inter', system-ui, sans-serif;
--forumulate-host-focus-ring: 2px solid #0f766e;
}<forumulate-widget org="acme" space="docs" mode="ask"></forumulate-widget>For each variable the SDK reads the --forumulate-host-* name first, then --fd-*, then --forgedeck-host-*, and uses the first one your page sets. A page written against an older spelling keeps working unchanged.
Precedence per option: what you pass → your page's variable → the widget's default. hostVars: false (or the host-vars="false" attribute) turns the middle step off. The hosted scripts (/embed/*.js) do the same for their accent when no data-accent is given.
floatRoom: floating elements and a consent banner
While a consent banner covers the bottom of the viewport, --forumulate-safe-bottom on <html> says by how many pixels. We write the same value under its first name, --fd-safe-bottom, which consent platforms such as Cookie Munch already read and write. Every floating element adds it to its bottom, reading our name first:
.my-launcher {
position: fixed;
bottom: calc(20px + var(--forumulate-safe-bottom, var(--fd-safe-bottom, 0px)));
}Ours all do: the ask-AI button and panel, the shop cart, the forum timeline pill, the auto-refresh toast, the preview ribbon, the hosted ask, FAQ and changelog launchers, and the room a floating chat embed reserves at the foot of the page.
Where the value comes from:
A consent manager we adapt (Cookie Munch, OneTrust, Cookiebot, Osano, Usercentrics, Didomi, TCF, …): our adapter measures its banner and writes the variable as it moves.
A CMP that implements
window.__fdConsentnatively, or a host page that wrote one: we read__fdConsent.layout.bottomInset()and followlayout.on('change'), and mirror the value onto both names.Your own sticky footer: set
--forumulate-safe-bottom(or--fd-safe-bottom) in your stylesheet. At 0 we remove our inline value rather than writing0px, so yours is never overridden by a banner that is not there.
The safe-bottom inset is layout, not theme: it is never in a theme and never set when no banner is visible.