Custom themes
Recolor the Jotura desktop app with one JSON file in your vault: turning it on, every token it accepts, contrast targets, ten starter palettes, and what happens when the file breaks.
A custom theme is one file in your vault, Jotura/theme.json. Turn on Custom theme under Settings, Appearance, and Jotura writes that file with the palette of the built-in theme you have selected. Change any color in it, save, and the app repaints as soon as the file lands on disk.
The file is an ordinary vault file, so it syncs to your other computers with your notes, and any text editor or the jotura CLI can change it. Themes set colors only. Fonts have their own settings, and there is no custom CSS. Themes apply to the desktop app. The Android app keeps its own appearance.
Turning it on
- Open Settings and find the Appearance section.
- Pick the built-in Theme you want to start from. Its colors become the seed for your file.
- Switch on Custom theme.
Jotura creates a Jotura folder at the root of the vault, if there is not one already, and writes Jotura/theme.json. The seeded file is named after its base, such as Graphite (custom), and holds that theme’s ten core colors for both light and dark. Some built-ins seed a few extra tokens as well.
If Jotura/theme.json already exists, because it synced from another computer or you wrote it yourself, Jotura uses it as it is and writes nothing.
An Open theme file button appears under the switch and opens the file in a tab. The Theme row then shows an extra card carrying your file’s name and the label on <base theme>. Picking a different built-in card while the custom theme is on changes the base your file layers over.
What is stored where
Theme and Custom theme are vault settings, stored as themeName and customThemeEnabled in Jotura/settings.json. Every computer that opens the vault gets the same look. Mode (System, Light, or Dark) stays on each device, so one computer can follow the operating system while another stays dark. With Mode on System, Jotura follows the operating system as it switches.
The file format
The file is a JSON object with an optional name and two optional palettes, light and dark. At least one palette is required. Jotura uses the palette that matches the current mode.
{
"name": "Harbor",
"light": {
"accent": "oklch(48% 0.14 200)",
"accent-contrast": "#ffffff"
},
"dark": {
"accent": "oklch(76% 0.13 200)"
}
}
The file layers over the selected built-in theme. A token you leave out keeps the built-in’s value, so the example above is complete: it changes the accent and nothing else. A palette you leave out keeps that whole mode on the built-in.
| Rule | Detail |
|---|---|
name |
Shown on the custom card in Settings. Missing or blank reads Custom. |
| Keys | Token names from the tables below, without the leading --. |
| Values | Any CSS color the app’s WebView accepts: hex such as #1b1035, rgb(), hsl(), oklch(), or color-mix(). |
| Applying | Saving the file applies it. So does a change from another editor, from the CLI, or from sync. |
| Mistakes | Unknown tokens and unusable values are skipped one by one and listed under the switch. See When the file is broken. |
Core tokens
These ten paint almost everything. Most other tokens are mixed from them, so changing a core token also moves everything derived from it.
| Token | What it paints |
|---|---|
bg |
The editor and the main page |
bg-sidebar |
The file tree, the tab bar, and the toolbar |
bg-hover |
Rows and buttons under the mouse |
bg-active |
The selected file in the tree and the active tab |
fg |
Body text and headings |
fg-muted |
Secondary text such as dates, folder paths, and finished tasks |
border |
Dividing lines and table rules |
accent |
Links, primary buttons, ticked checkboxes, and focus rings |
accent-contrast |
Text drawn on top of the accent color |
danger |
Delete actions and error messages |
A good way to start is with three colors: a background, a text color, and one accent. Make bg-sidebar, bg-hover, bg-active, and border small lightness steps away from bg, and the derived tokens fall into place.
Derived tokens
Each of these follows the core tokens by default. Override one by name when the computed value does not suit your palette.
| Token | Default |
|---|---|
card-bg |
bg |
hairline |
fg at 8% over transparent |
control-bg |
card-bg |
control-bg-hover |
bg-hover |
control-border |
fg at 18% over bg |
switch-off-bg |
fg at 20% over transparent |
scrollbar-thumb |
fg at 16% over transparent |
scrollbar-thumb-hover |
fg at 28% over transparent |
scrollbar-thumb-active |
accent at 55% over transparent |
editor-cursor |
fg |
editor-selection-bg |
accent at 20% over transparent |
editor-source-bg |
bg |
editor-source-fg |
fg |
editor-gutter-bg |
fg at 5% over bg |
editor-gutter-fg |
fg-muted at 70% over bg |
editor-active-line-bg |
fg at 3% over transparent |
editor-active-gutter-bg |
fg at 10% over bg |
danger-bg-hover |
danger at 9% over transparent |
task-done-strike |
fg-muted at 45% over transparent |
task-checkbox-border |
control-border |
The editor-source-*, editor-gutter-*, and editor-active-* tokens color source mode, the raw Markdown view with line numbers described in The editor.
Per-mode tokens
These have one fixed default for light mode and another for dark mode. They do not follow your core colors, so a dark palette that leaves them out keeps whatever the current mode provides.
| Group | Tokens |
|---|---|
| Dialogs and switches | overlay, shadow, switch-thumb |
| Warning banners | warning-bg, warning-border, warning-fg |
| Source mode syntax | editor-syntax-heading, editor-syntax-strong, editor-syntax-emphasis, editor-syntax-link, editor-syntax-string, editor-syntax-keyword, editor-syntax-comment, editor-syntax-number, editor-syntax-meta, editor-syntax-code, editor-syntax-quote, editor-syntax-list, editor-syntax-punctuation |
| Version history diffs | diff-add-bg, diff-add-word-bg, diff-add-fg, diff-del-bg, diff-del-word-bg, diff-del-fg, diff-hunk-bg, diff-hunk-fg |
| File badges | badge-md, badge-js, badge-json, badge-ts, badge-py, badge-rs, badge-html, badge-css, badge-pdf, badge-doc, badge-sheet, badge-slides, badge-image, badge-txt, badge-generic |
Two exceptions follow a core token in both modes: badge-md uses accent, and diff-hunk-fg uses fg-muted. The file badges are the small colored letters beside each file in the sidebar. The diff tokens color the comparison view in Version history.
Contrast targets
Contrast ratio measures how far text stands out from what is behind it, from 1:1 (invisible) to 21:1 (black on white). Every built-in theme is tested against these minimums in both modes:
| Pair | Minimum |
|---|---|
fg on bg |
7:1 |
fg on bg-sidebar |
7:1 |
fg-muted on bg |
4.5:1 (7:1 in the Contrast theme) |
accent on bg |
4.5:1 |
accent-contrast on accent |
4.5:1 |
Jotura does not check your file. Run your hex values through any WCAG contrast checker. In oklch() the first number is lightness, so raising or lowering it fixes contrast without shifting the hue.
One look in both modes
The seeded file holds separate light and dark palettes. For a single look, such as a dark theme that never turns light, put the same palette under both light and dark, then set Mode to match. Tokens your file leaves out still come from the current mode. The per-mode tokens are where this shows: a dark palette displayed in light mode keeps light mode’s dark badge letters and light diff backgrounds unless the file sets them too.
Starter palettes
Ten complete theme files are available to download. Each puts one palette under both light and dark, sets between 38 and 41 tokens including the syntax, diff, and warning colors, and looks the same in either mode. Download one, paste its contents into Jotura/theme.json, and adjust from there.
| Palette | Look | fg on bg |
|---|---|---|
| Synthwave | Dark. Deep purple with hot magenta. | 15.5:1 |
| Phosphor | Dark. A green terminal, every color a shade of green. | 15.9:1 |
| Blueprint | Dark. Architect’s blue with yellow accents. | 10.1:1 |
| Abyss | Dark. Near-black ocean with glowing cyan. | 15.8:1 |
| Molten | Dark. Charcoal and lava orange. | 16.5:1 |
| Aurora | Dark. Midnight navy with a mint accent. | 16.3:1 |
| Risograph | Light. Cream paper, blue ink, fluorescent pink. | 11.2:1 |
| Bubblegum | Light. Pastel pink with a teal accent. | 14.3:1 |
| Brutalist | Light. White page, yellow sidebar, black rules, blue links. | 21:1 |
| Game Boy | Light. The original handheld’s four greens. | 6.0:1 |
Nine of the ten meet every target above. Game Boy has only four shades to work with, so its text reaches 6.0:1 on the page and 5.0:1 on the sidebar, short of 7:1.
Editing from the command line
Jotura/theme.json is a plain file, so the jotura CLI reads and writes it like a note. A path without an .md extension has no frontmatter, so every operation covers the whole file. Replace the whole theme with a downloaded palette:
jotura write Jotura/theme.json < synthwave.json
Change one color. The Synthwave file sets its accent under both palettes, so the match appears twice and needs --all. Without it, the command exits 4 (Ambiguous) and writes nothing.
jotura edit Jotura/theme.json --replace '"accent": "#ff4fb0"' --with '"accent": "#ff7ac4"' --all
The desktop app picks up either change while it runs. If the switch is off, the file waits: turning Custom theme on later uses the file you wrote and seeds nothing. The safe-edit loop with --if-hash is in Editing from the CLI.
When the file is broken
Jotura applies whatever it can use from the file and lists each problem under the switch in Settings. Only a file it cannot read as a theme at all falls back to the built-in entirely.
| Problem | What you see | What shows on screen |
|---|---|---|
| The file is not valid JSON | Invalid JSON: followed by the parser’s message |
The built-in theme, unchanged |
| The file is JSON but not an object | Theme file must be a JSON object |
The built-in theme |
Neither light nor dark is an object |
Theme file needs a "light" or "dark" object |
The built-in theme |
| One palette is not an object | "light" must be an object; ignored |
The other palette still applies |
| A token name Jotura does not know | light.<name>: unknown token; ignored |
Every other token still applies |
| A value that is not a usable color | dark.<name>: not a colour the app can use; ignored |
Every other token still applies |
| The file is deleted or missing | Jotura/theme.json is missing from the vault. with a Recreate button |
The built-in theme |
Recreate writes a fresh file seeded from the built-in theme currently selected. Turning Custom theme off stops using the file and never deletes it.
Limits
- Colors only. Fonts and font sizes are separate rows under Appearance, and layout, spacing, and icons cannot change.
- One active theme file per vault. Keep spares elsewhere in the vault and copy the one you want into
Jotura/theme.json. - No custom CSS. A theme or CSS snippet written for another app does not apply, and copying its colors into this file is the closest equivalent.
- Desktop only. The Android app ignores the file.
Every other Appearance setting is in the Settings reference.