Theming
Every Cobuntu widget — auth, cart, messages, notifications, nav,
search — reads its colors, radii and fonts from a shared set of
--cobuntu-* CSS custom properties. There are three ways to
control them, in order of how much work they are:
- Do nothing — auto-theme. The widget bundle fetches your
community's brand config on mount and writes the right vars
to
:rootfor you. This is the default and what most customers want. - Override per page — set the vars yourself in a
<style>block on the landing. Useful when the auto-fetched theme isn't what you want, or when you don't have a Cobuntu community at all (rare). - Override per widget mount — set vars inline on each
<div data-cobuntu-*>mount node. Useful when one widget on a page needs to look different from the others.
Auto-theme (default)
On every page that mounts at least one widget script, the bundle:
- Reads
location.hostname(e.g.yourdomain.com). - Hits
GET https://api.cobuntu.com/api/communities/by-domain/<host>— a public endpoint that returns the community'sthemeConfig. - Maps your brand colours to
--cobuntu-*vars and injects a<style>tag into<head>— wrapped in a low-priority@layer cobuntu-preset.
Auto-theme applies your colours only — your brand colour to the
badges + accent, and your background/text to the drawer panels. It
does not set the icon-button shape: the triggers (cart,
messages, notifications, account) default to a flat, transparent
chrome. Any shape — borders, pills, fills, padding — is entirely your
own CSS (--cobuntu-border, --cobuntu-bg, --cobuntu-radius, …).
There are no "flat / glass / bordered" modes to pick from; you just
write the CSS you want.
The same widget bundle runs on the community's own pages (e.g.
yourdomain.com/events) and on your landing — the visual result is
identical.
Your own CSS always wins. Because the auto-theme is injected
inside @layer cobuntu-preset, it's a default — any
--cobuntu-* value you set yourself (in a normal, unlayered
<style>/CSS rule, or inline on a mount) overrides it, regardless
of source order. So you never have to fight the auto-theme: set only
the vars you want to change, and the rest fall back to your brand
config. (Unlayered CSS beats any @layer in the cascade — this is a
standard CSS guarantee, not a Cobuntu trick.)
Idempotent. The widget checks for two style IDs before injecting:
cobuntu-community-theme-vars(its own injection)cobuntu-widget-theme-style(the community-app's<WidgetThemeStyle>React component, which runs before any widget script on community-app pages)
If either is present, the fetch is skipped. So even if you have multiple widgets on the page, only one fetch happens.
Failure mode. If the hostname isn't registered as a Cobuntu custom domain, the endpoint returns 404 and the widget falls back to its built-in defaults (white background + dark text + gold badge). Nothing crashes; no console error in production builds.
Override per page
Auto-theme is fine for 90% of customers, but if you want to hard-pin the values — for QA, for a temporary brand override, or because your landing is on a host that isn't a Cobuntu custom domain — set the vars yourself:
<style>
:root {
--cobuntu-bg: #0A0A0A;
--cobuntu-color: #E0E0E0;
--cobuntu-badge-bg: #D4AF37;
--cobuntu-badge-text: #000000;
--cobuntu-radius: 0px;
--cobuntu-card-radius: 22px;
--cobuntu-input-radius: 12px;
--cobuntu-font: "Montserrat", sans-serif;
--cobuntu-heading-font: "Playfair Display", serif;
--cobuntu-link-color: #D4AF37;
--cobuntu-drawer-bg: #0A0A0A;
--cobuntu-drawer-color: #E0E0E0;
--cobuntu-primary-btn-bg: linear-gradient(135deg, #D4AF37, #F2D47E);
--cobuntu-primary-btn-text: #000000;
}
</style>Variables you set this way always win over the auto-fetched
ones — the auto-theme ships inside @layer cobuntu-preset, and any
unlayered CSS rule (like the <style> above) beats a layer in the
cascade no matter where it sits in the document. You only need to
declare the vars you want to change; everything else falls back to
the auto-theme. Just keep your rule unlayered (a plain :root {…}
— don't wrap it in your own @layer).
Override per widget mount
For one-off cases (a "dark mode toggle" on a single button, a brand-color cart drawer on an otherwise neutral page), use inline styles on the mount node. Variables inherit, so anything you set on the parent flows through to the widget's internal markup.
<div
data-cobuntu-cart
style="
--cobuntu-bg: #ffffff;
--cobuntu-color: #1a1a1a;
--cobuntu-badge-bg: #ef4444;
"
></div>Full variable contract
These vars are part of the v1 stable contract. Names and meaning won't change in v1; new vars may be added in minor versions.
Trigger surface
| Variable | Type | What it controls |
|---|---|---|
--cobuntu-bg | color | Button / icon background |
--cobuntu-color | color | Foreground (text + icon stroke) |
--cobuntu-hover-bg | color | Background on hover (falls back to bg) |
--cobuntu-hover-color | color | Foreground on hover (falls back to color) |
--cobuntu-border | shorthand | Optional border on the trigger |
--cobuntu-radius | length | Button corner radius |
--cobuntu-padding | shorthand | Button padding (button variants only) |
--cobuntu-font | font-family | Body font for trigger labels |
--cobuntu-font-size | length | Trigger label font size |
--cobuntu-font-weight | weight | Trigger label weight |
--cobuntu-letter-spacing | length | Trigger label spacing |
--cobuntu-text-transform | keyword | Trigger label transform |
Badge
| Variable | Type | What it controls |
|---|---|---|
--cobuntu-badge-bg | color | Unread-count badge background |
--cobuntu-badge-text | color | Unread-count badge foreground |
Drawer / panel (auth + cart + notifications)
| Variable | Type | What it controls |
|---|---|---|
--cobuntu-drawer-bg | color | Drawer panel background (falls back to --cobuntu-bg) |
--cobuntu-drawer-color | color | Drawer panel foreground (falls back to --cobuntu-color) |
--cobuntu-card-radius | length | Inner card corner radius |
--cobuntu-input-radius | length | Input field corner radius |
--cobuntu-primary-btn-bg | color/gradient | "Accept" / "Save" button background |
--cobuntu-primary-btn-text | color | "Accept" / "Save" button foreground |
--cobuntu-link-color | color | Drawer link color |
--cobuntu-accent | color | One-token brand colour for the account avatar + sign-in button (the explicit *-bg/*-text tokens still win) |
--cobuntu-on-accent | color | Foreground on --cobuntu-accent |
--cobuntu-drawer-hover | color | Row / item hover background. Defaults to a color-mix off the drawer text colour, so it adapts to any brand automatically |
--cobuntu-drawer-border | color | Dividers / borders inside the drawer. Same auto-adapting default |
--cobuntu-backdrop | color | The dim scrim behind an open drawer |
--cobuntu-danger | color | Destructive actions (e.g. "Remove", account delete) |
Brand-agnostic by default. Every drawer surface that isn't an explicit brand colour (hovers, dividers, the close affordance) derives from the drawer's own text colour via
color-mix, so the widgets adapt to a light or dark brand with zero config. Set--cobuntu-accent+--cobuntu-drawer-bg/-textand the whole drawer reskins to your brand.
How auto-theme maps your themeConfig
For reference — these are the exact field-to-var mappings the widget applies when it fetches your theme:
themeConfig.bgColor → --cobuntu-bg + --cobuntu-drawer-bg
themeConfig.textColor → --cobuntu-color + --cobuntu-drawer-color
+ --cobuntu-hover-color
themeConfig.brandColor → --cobuntu-badge-bg
themeConfig.primaryBtnText → --cobuntu-badge-text
themeConfig.buttonRadius → --cobuntu-radius
themeConfig.inputRadius → --cobuntu-input-radius
themeConfig.cardRadius → --cobuntu-card-radius
themeConfig.bodyFont → --cobuntu-font
themeConfig.headingFont → --cobuntu-heading-font
themeConfig.linkColor → --cobuntu-link-color
themeConfig.primaryBtnBg → --cobuntu-primary-btn-bg
themeConfig.primaryBtnText → --cobuntu-primary-btn-textThe themeConfig itself is what you edit in
cobuntu-admin → Customize → Branding. Changes there reflect on
your landing within seconds of save (no widget version bump needed
— each page-load fetches fresh).
Versioning
The variable names + auto-theme behavior are v1 stable. They
won't change while /widgets/v1/*.js is current. New widgets
shipped under v1 read the same vars. A future v2 will live at
/widgets/v2/*.js and may introduce new vars or rename existing
ones; both versions will coexist for the standard deprecation window.