Branding¶
Operators can change the web-frontend's look without rebuilding the image:
- the app name in the browser title and the interface texts
- any color of the design palette
- the UI font
- the logo, favicons and built-in icons
- where the logo and the in-app help links point
- whether the attribution footer is shown at all
- translated texts
- additional CSS
The web-frontend server reads everything from a branding directory at runtime. Nothing is required: with no directory, or an empty one, the built-in defaults are used.
The branding directory¶
The web-frontend reads the directory named by BASEROW_BRANDING_DIR, which
defaults to /baserow/branding. In the all-in-one image the default is
$DATA_DIR/branding, i.e. /baserow/data/branding on the data volume.
branding/
├── branding.json app name, colors, font, translations, links
├── theme.css extra CSS, loaded after the built-in styles
├── img/ logo and favicon overrides
│ ├── logo.svg main logo (176×29)
│ ├── logoOnly.svg square mark (30×30), used in notifications
│ ├── favicon_16.png
│ ├── favicon_32.png
│ ├── favicon_48.png
│ └── favicon_192.png
├── icons/ overrides for the built-in `baserow-icon-*` icons (24×24 SVG masks)
└── files/ any other assets referenced from theme.css, e.g. fonts
A copy of this layout lives in deploy/branding-example/.
Files in img/ and icons/ replace the built-in file with the same name; any
file you don't provide keeps its default. All assets are served from
/_branding/assets/<folder>/<file>. Allowed file types are svg, png, jpg,
webp, gif, ico, woff, woff2, ttf and otf.
branding.json¶
{
"appName": "Acme Data",
"colors": {
"color-primary-500": "#0f766e",
"palette-neutral-1200": "#1f2933"
},
"fontFamily": "'Brand Sans', sans-serif",
"siteUrl": "https://acme.example",
"docsUrl": "https://docs.acme.example",
"siteTitle": "Acme Data",
"showAttribution": true,
"messages": {
"en": { "some": { "translation": { "key": "Replacement text" } } }
}
}
appName: the product name,Saveroomby default. It is shown in the browser tab (Page | Acme Data) and wherever the interface names the product ("Welcome to Acme Data", "New to Acme Data?"): those translations link to theapp.namekey, which this value fills in every language. Max 64 characters. The backend's emails and API docs only see theBASEROW_BRANDING_APP_NAMEenvironment variable, notbranding.json, so set the variable to rename those too.colors: overrides color tokens. Two kinds of names are accepted:- Palette tokens (
palette-<hue>-<step>) are the raw scale. Hues areneutral,blue,green,red,cyan,yellow,magentaandpurple. Overriding a palette token recolors everything built on it. - Semantic tokens (
color-<role>-<step>) coverprimary,neutral,success,warning,error,yellow,purple,pink,brownandcyan. Overriding one changes only that role.
The complete list, with defaults, is in
web-frontend/modules/core/assets/scss/colors.scss. To rebrand the primary
color, override the whole palette-blue-* scale, or the color-primary-*
tokens.
Values must be CSS colors: hex, rgb(), hsl(), oklch() and similar, or
named colors. Unknown tokens and invalid values are ignored with a warning in
the web-frontend logs.
- fontFamily: a CSS font-family value for the whole UI. Load custom
fonts with @font-face in theme.css.
- siteUrl: where the attribution logo links to — the sidebar footer, the
header of a publicly shared view, and the "Powered by" block on public form
views.
- docsUrl: where the in-app documentation and help links point: the
dashboard resource cards, the automation docs button, the email tester, the
role and element-visibility help links.
Both must be http(s) URLs or root-relative paths (/docs). Anything else,
javascript: above all, is ignored with a warning: these values go straight
into a link.
- siteTitle: the title and alt text on the attribution logo. Falls
back to appName, then to Saveroom. Max 160 characters.
- showAttribution: set to false to remove the attribution entirely —
the sidebar footer logo, the shared-view header logo, the public form
"Powered by" block and the fork and upstream credits on the admin version
panel all stop rendering.
- messages: translation overrides per locale, using the same keys as
web-frontend/**/locales/<locale>.json. The "Powered by" label is
formViewPoweredBy.poweredBy in the database module.
theme.css¶
Plain CSS that is loaded after the built-in styles and the generated color
variables, so it can override anything. Reference your own assets from
files/:
@font-face {
font-family: 'Brand Sans';
src: url('/_branding/assets/files/fonts/BrandSans-Regular.woff2') format('woff2');
}
.logo img {
height: 24px;
}
Environment variables¶
These take precedence over branding.json, and empty values count as unset:
| Variable | Purpose |
|---|---|
BASEROW_BRANDING_DIR |
Branding directory path (default /baserow/branding). |
BASEROW_BRANDING_APP_NAME |
Overrides appName. Also read by the backend, for the name in emails and the API docs title; give it to the backend and Celery containers as well. |
BASEROW_BRANDING_COLORS |
JSON object merged over colors, e.g. {"color-primary-500":"#0f766e"}. |
BASEROW_BRANDING_SITE_URL |
Overrides siteUrl. |
BASEROW_BRANDING_DOCS_URL |
Overrides docsUrl. |
BASEROW_BRANDING_SITE_TITLE |
Overrides siteTitle. |
BASEROW_BRANDING_SHOW_ATTRIBUTION |
Overrides showAttribution; true/false. |
Applying changes¶
No restart is needed. The server re-reads the directory at most every two seconds, so a page reload picks up edits. Asset responses carry a one-minute cache with an ETag.
Deployment¶
Docker Compose¶
Mount the directory read-only into the web-frontend service. The volume is
shown commented out in the root docker-compose.yaml:
web-frontend:
volumes:
- ./branding:/baserow/branding:ro
All-in-one image¶
Put the files in branding/ inside the data volume (/baserow/data/branding),
or mount a directory there.
Helm¶
Set the branding values. The chart renders them into a ConfigMap mounted at
/baserow/branding:
branding:
appName: "Acme Data"
colors:
color-primary-500: "#0f766e"
fontFamily: ""
siteUrl: "https://acme.example"
docsUrl: "https://docs.acme.example"
siteTitle: "Acme Data"
showAttribution: true
messages: {}
themeCss: |
.logo img { height: 24px; }
files:
img/logo.svg: "<base64 of logo.svg>"
faviconBase64: "<base64 of favicon.ico>" # also served at /favicon.ico
A ConfigMap holds at most about 1 MiB. For larger asset sets, create a
PersistentVolumeClaim holding a complete branding directory and set
branding.existingClaim. The inline values are then ignored, except
faviconBase64.
Scope and limits¶
- Plugins that register their own logo component
(
getLogoComponent()) still take precedence overimg/logo.svg. - A form view's own "show logo" setting still applies:
showAttributiononly ever hides the block further, it never forces it back on. - Icons from the Iconoir icon font (
iconoir-*classes) are font glyphs and cannot be swapped file by file; restyle or hide them withtheme.css. - Application Builder sites keep their per-application theme settings.
- Backend-rendered content, such as emails, is not affected.