PlantUML theme packs — building, distributing, and enforcing brand themes
PlantUML ships with 20+ themes, but they don’t cover corporate brand colour, dark mode, or print colour. This post walks through “DIY theme + internal publish” in full.
Three flavours of a theme
PlantUML themes live at 4 levels:
| Level | Who uses it | File format |
|---|---|---|
| skinparam | Single diagram / single .puml |
Inline |
!theme file |
Single team / many diagrams | .puml file |
| Built-in skin pack | PlantUML itself | Built-in |
| CSS / SVG transform | Post-processing | pipeline |
The first three have been supported since PlantUML 1.2018. CSS processing is “transform after render” pipeline.
Approach 1: in-line skinparam (smallest)
Put the skin at the top of every diagram:
1 | @startuml |
Repeated per diagram — verbose, not great for “team of 30 engineers”.
Improvement: a shared skins/standard.puml:
1 | !global |
Each diagram prepends:
1 | !include skins/standard.puml |
Less repetitive than per-diagram but !include paths differ across IDEs (VS Code plantuml.includepaths / CLI -I); team collaboration still hurts.
Approach 2: real !theme packs
The !theme syntax from PlantUML 1.2018+ is the “centralised theme resource” story.
Layout
1 | themes/ |
puml-theme.css (CSS variables)
1 | /* Brand colours: violet + warm grey */ |
puml-theme.puml (PlantUML syntax)
1 | !$brand_primary = "#6B5ACD" |
Publish to internal npm
1 | cd themes/company-brand |
Or simpler: push to an internal git repo:
1 | git remote add internal git@git.internal.company.com:design/plantuml-theme-company.git |
Team use
Each diagram:
1 | @startuml |
VS Code PlantUML plugin reads !theme:
- if
plantuml-theme-company-brandnpm package is installed, automatic discovery - otherwise configure
!theme company-brand from <path>
Approach 3: post-render transform (CSS / SVG)
After PlantUML renders the SVG, re-color via SVG transform / CSS — fits “we already use the PlantUML service but want to add a corporate theme”.
sed-based SVG colour replace
1 | plantuml -tsvg diagram.puml |
Brute but effective — drawbacks:
- PlantUML versions emit SVG with different field names (“stroke” vs “Stroke”).
- Schema varies by diagram type.
Python transform (more reliable)
1 | import re |
Drop into a CI pipeline:
1 | - name: Render PlantUML |
Approach 4: enforce theme consistency at PR review
Inside the team, only .puml files declare !theme company-brand — CI verification:
1 | # Pre-commit / GitHub Action |
Missing theme → CI fails. Conforming diagrams look like:
1 | @startuml |
Dark mode / light mode auto-switching
PlantUML default doesn’t switch on system preference, but there are workarounds.
Approach A: CSS prefers-color-scheme media query
1 | /* In the wiki theme CSS */ |
Build-time generate 2 SVGs (light + dark):
1 | plantuml -tdefault -tsvg diagram.puml # light |
In HTML:
1 | <img src="diagram.svg" class="diagram-light" /> |
Approach B: JavaScript toggle class
1 | document.querySelectorAll('.plantuml-theme-toggle').forEach(el => { |
Theme pack contributes:
1 | body.dark .diagram { filter: invert(1) hue-rotate(180deg); } |
Brute but effective — invert the SVG globally; colour accuracy suffers a bit but works.
Theme version management
For npm publishing, follow semver:
1 | npm version patch # minor skin param tweaks |
Diagrams !theme company-brand without version pinning → use latest. To pin:
1 | !theme company-brand@1.2.3 |
Advanced capabilities
Custom !function
A theme pack can introduce new keywords:
1 | !function $brand_node($name) |
Team diagrams use it directly:
1 | %brand_node("App1") |
Custom !pragma
1 | !pragma company_layout |
In the theme file:
1 | !procedure company_layout |
Integrate via jsDelivr / CDN
Publish to a GitHub repo, then jsDelivr pulls it:
1 | git tag v1.0.0 |
PlantUML CLI online include:
1 | plantuml -tpng -o /tmp -include "https://cdn.jsdelivr.net/..." diagram.puml |
Deployment recommendation
By team size:
| Team size | Approach | Reason |
|---|---|---|
| 1-3 people | Inline skinparam | Direct |
| 4-20 | !theme file + internal git |
Maintainable, high reuse |
| 20+ | npm package + version pin | Easy distribution; CI enforces consistency |
| Multi-product / multi-team | Multiple theme packs | product / theme isolation |
Recap
- PlantUML themes have 4 layers from “inline” to “publish a package”.
- Mutable skinparam alone covers most enterprise needs — don’t jump straight to npm.
- CJK fonts always set
skinparam defaultFontName. - Team consistency → CI verification → reject diagrams without a theme.
Next
- Title: PlantUML theme packs — building, distributing, and enforcing brand themes
- Author: puml.online
- Created at : 2026-07-30 11:09:00
- Updated at : 2026-08-14 21:34:29
- Link: https://puml.online/blog/plantuml-theme-pack-en/
- License: This work is licensed under CC BY-NC-SA 4.0.