Share
Explore

Create a Custom Themes

How to Get Started

Open NotePlan, click on “Preferences”, choose a theme as template and click on “Copy & Customize”:

CleanShot 2021-03-03 at 20.15.53@2x.png

This will copy the theme JSON file into NotePlan’s synced folder structure from where you can modify it. Any changes you make on the theme will be automatically synced to all your other devices, including iOS.

You can also import other themes by clicking on “Import Theme...” in the same window.

JSON File
The theme file contains two major keys: “editor” and “styles”. The “editor” key defines the main colors of NotePlans user interface:

"editor": {
"backgroundColor": "#ffffff", // Base background color
"altBackgroundColor": "#FAFFFF", // Slighlty lighter
"tintColor": "#d87001",
"tintColor2": "#0091f8",
"textColor":"#333333",
"toolbarBackgroundColor": "#F2F3F5",
"toolbarIconColor": "#444444",
"menuItemColor": "#444444",
"shouldOverwriteFont": true
},

The “styles” key contains all text styles, like font, text size, color, etc. for the titles, open tasks, closed tasks, quotes, etc.:

"styles": {
"body": {
"font": "AvenirNext-Regular",
"size": 16,
"color": "#333333",
},
"title1": {
"color": "#000000",
"size": 28
},
"title2": {
"color": "#000000",
"size": 24
},
...

Style Attributes
Following attributes are valid for style keys with example values:

"lineSpacing": 3,
"paragraphSpacing: 8,
"paragraphSpacingBefore: 8,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"size": 24,
"type": "italic",
"underlineStyle": 1,
"underlineColor": "#000000",
"strikethroughStyle": 1,
"strikethroughColor": "#000000"

Strikethrough and underline styles have a thicker line the higher the number you are using for the ...style attribute. Adding a color is optional.

Colors
Colors support ARGB written as hexacode (#AARRGGBB). You can omit the A value and write: #FF0000 to get red for example or #66FF0000 to get transparent red. color or foregroundColor is the text color. You can also define backgroundColor to change the background behind text (as opposed to the whole editor background).

Link Colors
The color for following keys will be overwritten by tintColor, because they are all converted to links and only one link color can be used (limitation in Apple’s text editor framework):

"link"
"schedule-to-date-link"
"done-date"
"schedule-from-date-link"
"note-title-link"
"hashtag"
"attag"
"phonenumber"

Fonts
The font of most keys, including the following is overwritten by the app preferences under “Editor”, so that you can change the font and font-size from within the app without having to modify a theme:

"body"
"title1"
"title2"
"title3"

You can turn off the overwriting and define your own font by setting following attribute under the “editor” key in a theme file:

"shouldOverwriteFont": false

It’s set to true by default.

Font Names
You can look up the correct font name using the app “Font Book”. Copy the “PostScript name” value into the theme file:

CleanShot 2021-02-26 at 10.10.32.png

In the theme file change the value for “font” in the “body” key for example:

"body": {
"font": "AvenirNext-Regular",
"size": 16,
"color": "#CBCCC6",
},

Custom Fonts on iOS
On iOS the font will revert to the System font if you choose a custom font on Mac which you have installed from the internet. To install custom fonts on iOS use an app like: or . Follow the instructions when you open FontCase.

Bold and Italic
If you use a custom font, you need to add the correct bold/italic font names from your custom font to the “bold” and “italic” keys, otherwise they will be overwritten by the custom font you picked and won’t render as bold/italic.

For “Avenir Next” this would be “AvenirNext-BoldItalic” for example:

"italic": {
"type": "italic",
"color": "#95E6CB",
"size": 16,
"font": "AvenirNext-BoldItalic"
},

System Fonts
If you want to use the system fonts, you can use following values for body, italic and bold. It will automatically use the system’s font:

Bold: .AppleSystemUIFontHeavy
Italic: .AppleSystemUIFontItalic
Normal: .AppleSystemUIFont

Spacing
If you want to change the paragraphSpacing, lineSpacing or paragraphSpacingBefore for the titles, you need to add the attributes to the corresponding "title-markX" keys instead of ”titleX” keys.

By default the paragraphSpacing is different from the lineSpacing. In most apps these values are the same. If you want to have the same value for both, add them to the ”body” key. Make sure to add it also to the “tabbed” key which styles anything that is indented.

HeadIndent
This defines the indentation of the first line vs the other lines inside a paragraph. There is a difference between the lines if the line is a task for example. In case of a task there is a task icon in the first line and it shouldn’t indent along with the text, that’s what headIndent is achieving:

image.png

Tasks and Bullets
Tasks and bullets are styled by the ”todo” key. There is no separation, because the preferences determine what a task is and what a bullet is. For example, * task is by default a task, but if you turn it off in the preferences, it becomes a bullet and - task can be a task or the standard markdown: - [ ] task.

Task States (Open, Scheduled and Canceled)
All state styles are covered under ”checked”. In the background a regular expression is defined to identify them in the text. They are bundled into one style to reduce computing power required.

special-char
This refers to * and - which are special characters in NotePlan. By default a different font is assigned to those two characters (Menlo-Regular) to make them look better. This font is not overwritten by the one defined in the preferences.

Titles
title1 covers headings with a single pound # Heading, title2 with two pounds ## Heading 2 and title3 covers anything else, from ### Heading 3 and more pounds. There is no support for title4 or higher.

Building Custom Styles with Regular Expression
Every style is based on a regular expression to detect the text. The regular expressions are stored in a JSON file inside the app bundle, but you can add custom regular expressions to the theme JSON file.

Example 1 → ::highlighting::
Here is an example for a new style you can add below the existing ones for highlighting text by surrounding words with a double colon:

image.png

"highlighted": {
"regex": "(::)([^:]{1,})(::)",
"matchPosition": 2,
"isRevealOnCursorRange": true,
"backgroundColor": "#7745A2E5"
},

"highlighted-left-colon": {
"regex": "(::)([^:]{1,})(::)",
"matchPosition": 1,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#AA45A2E5",
"backgroundColor": "#7745A2E5",
},

"highlighted-right-colon": {
"regex": "(::)([^:]{1,})(::)",
"matchPosition": 3,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#AA45A2E5",
"backgroundColor": "#7745A2E5",
}

You can also overwriting the regular expression of an existing style by adding the ”regex” attribute.

Here the keys highlighted, highlighted-left-colon, and highlighted-right-colon were added. They all have a ”regex” attribute with the value "(::)([^:]{1,})(::)" which will find words surrounded by :: and apply the style defined in the same key.

Example 2 → !! flagging by importance
In this example you can change the background color of the full line from a light to a strong red tone to mark the priority using !, !! or !!! at the beginning of the line:

image.png

Code:

"flagged-1": {
"regex": "(^|\\v)(\\h*(\\*|-)\\h*(\\[ \\]\\h+|\\h+)\\!{1}\\h+.*)($|\\v)",
"matchPosition": 2,
"backgroundColor": "#22D0021B",
"headIndent": 33
},

"flagged-2": {
"regex": "(^|\\v)(\\h*(\\*|-)\\h*(\\[ \\]\\h+|\\h+)\\!{2}\\h+.*)($|\\v)",
"matchPosition": 2,
"backgroundColor": "#55D0021B",
"headIndent": 33
},

"flagged-3": {
"regex": "(^|\\v)(\\h*(\\*|-)\\h*(\\[ \\]\\h+|\\h+)\\!{3}\\h+.*)($|\\v)",
"matchPosition": 2,
"backgroundColor": "#AAD0021B",
"headIndent": 33
},
Example 3 → ~~Strikethrough~~
Add strikethrough style to a word using following styles. This works together with underline where you use single tilde characters left and right of the word:

image.png

With visible markdown characters:
image.png

Code:

"strikethrough": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))((\\~|_)\\3)(?=\\S)(.*?\\S)(\\3\\3)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 4,
"strikethroughStyle": 1,
"isRevealOnCursorRange": true,
"color": "#AACBCCC6",
"strikethroughColor": "#CBCCC6"
},

"strikethrough-left-tilde": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))((\\~|_)\\3)(?=\\S)(.*?\\S)(\\3\\3)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 2,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#44CBCCC6"
},

"strikethrough-right-tilde": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))(\\~|_)\\2(?=\\S)(.*?\\S)(\\2\\2)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 4,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#44CBCCC6"
},
Example 4 → ~Underline~

image.png

With visible markdown characters:
image.png

Code:

"underline": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))(\\~|_)(?=\\S)((?:(?!\\2).)*?\\S)(\\2)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 3,
"isRevealOnCursorRange": true,
"underlineStyle": 1,
"underlineColor": "#FFCC66"
},

"underline-left-tilde": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))(\\~|_)(?=\\S)((?:(?!\\2).)*?\\S)(\\2)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 2,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#44CBCCC6"
},

"underline-right-tilde": {
"regex": "(^|[\\W_])(?:(?!\\1)|(?=^))(\\~|_)(?=\\S)((?:(?!\\2).)*?\\S)(\\2)(?!\\2)(?=[\\W_]|$)",
"matchPosition": 4,
"isMarkdownCharacter": true,
"isHiddenWithoutCursor": true,
"isRevealOnCursorRange": true,
"color": "#44CBCCC6"
}

Regular Expression Attributes
"matchPosition" defines which regular expression group should be used for the styling. In this example every the regular expression has 3 groups, for example: (::). The count begins with 1. If you use 0 as position, it takes the full match including all groups.

"isHiddenWithoutCursor" will hide the matched text if the cursor is not inside the word.
"isRevealOnCursorRange" will reveal hidden text, if the cursor is inside.

\\ escapes a character in the regular expression which would otherwise alter the matching behavior, such as *. Make sure it’s always double escaped like in this example.

Create Links with Regular Expressions
You can use attributes to detect and display links. See following example:

"quick-link": {
"regex": ">([\\w\\-.]+)",
"matchPosition": 1,
"urlPosition": 1,
"type": "noteLink",
"prefix": "noteplan://x-callback-url/openNote?noteTitle="
},

This will detect text prefixed with > and create a clickable link, like >mynote. You need to define the ”type” as ”noteLink” so that NotePlan turns the text into a link.

A link has a URL. You can define which part of the matched string will be used as URL using the regex group position urlPosition. In this case ”urlPosition”: 1 is used.

The ”prefix” will prepend any string before the URL. In this case we are using a X-Callback-Url, so the link can be opened inside NotePlan: "noteplan://x-callback-url/openNote?noteTitle=". You can also use any web address. The final URL of >mynote for example would be:

"noteplan://x-callback-url/openNote?noteTitle=mynote"

In this case NotePlan would attempt to open a note with the title “mynote”. You can find all possible X-Callback-Urls .

Open Search with Regular Expressions
Following will kick off in-app searches on a delimited /search phrase/, for example for /meetings/ will open the search view in NotePlan and search for the text “meetings” in all your notes:

"note-search-link": {
"regex": "/(\\S[^/]*\\S)/",
"matchPosition": 1,
"urlPosition": 1,
"type": "link",
"prefix": "noteplan://x-callback-url/search?text="
},

NotePlan’s Regular Expressions
Below is a JSON file containing the default regular expressions for the existing themes, which you can use to get an idea and modify styles:

markdown-regex.json
7.6 kB

Resolving Conflicts
If you add a custom style it will be applied by default after the existing styles. It could overwrite an existing style and break the styling. To resolve this conflict, you can change the order in which the styles are applied. To control the order you can add a new key “orderedStyles” above “styles” which contains an ordered array of all style names. Include your custom style wherever needed to resolve the conflict.

Here is the current order of the existing styles:
"orderedStyles": ["title-mark1", "title-mark2", "title-mark3", "body", "quote-content", "bold", "bold-left-mark", "bold-right-mark", "italic", "italic-left-mark", "italic-right-mark", "boldItalic", "boldItalic-left-mark", "boldItalic-right-mark", "code", "code-left-backtick", "code-right-backtick", "special-char", "checked-todo-characters", "todo", "checked", "quote-mark", "tabbed", "link", "hashtag", "attag", "schedule-to-date-link", "done-date", "schedule-from-date-link", "note-title-link", "title1", "title2", "title3", "note-title-link"],

Change Existing Styles
You can not only modify the style attributes of existing styles, but you can also change the default regex. NotePlan will first look if there is a regex defined in your theme file and then it will fall back to the regex file.

Example → #### Heading 4
For example, NotePlan supports by default (v3.0.19) headings up to ###. So Heading 4 will look exactly like Heading 3. If you want to add support for Heading 4 and beyond, you can first modify the title3 regex to limit it to Heading 3, then add your own Heading 4+ style with a regex. Look up what the current regex is in the markdown-regex.json file above, then modify it.

Here is how the end result could look like:

"title3": {
"regex": "^\\h*(### )(.*)",
"matchPosition": 2,
"isRevealOnCursorRange": true,
"color": "#FFA759",
"size": 20
},

"title4": {
"regex": "^\\h*(####+ )(.*)",
"matchPosition": 2,
"isRevealOnCursorRange": true,
"color": "#F0A759",
"size": 18,
"underlineStyle": 1
},

”title3”s regex "^\\h*(###+ )(.*)" was modified to "^\\h*(### )(.*)" (basically the + was removed) and ”title4” was added. If you want to use it, make sure to delete your existing ”title3” style, then paste the above.

Example → Different Colors for Done / Canceled / Scheduled
Right now all three todo states have the same color (a transparent grey). But if you want to have different colors for each state, you can overwrite the checked style and add 2 more with a slightly different regex:

image.png

Here is the code:

"checked": {
"regex": "(^\\h*[\\*\\-]{1} |^\\h*[0-9]+[\\.\\)] )(\\[x\\] )(.*)",
"matchPosition": 0,

"color": "#88CBFFC6",
"headIndent": 33
},

"checked-canceled": {
"regex": "(^\\h*[\\*\\-]{1} |^\\h*[0-9]+[\\.\\)] )(\\[\\-\\] )(.*)",
"matchPosition": 0,

"color": "#44FFCCC6",
"headIndent": 33,
"strikethroughStyle": 1
},

"checked-scheduled": {
"regex": "(^\\h*[\\*\\-]{1} |^\\h*[0-9]+[\\.\\)] )(\\[\\>\\] )(.*)",
"matchPosition": 0,

"color": "#88CBCCFF",
"headIndent": 33
},

More Ideas
Mark key words like #important with a different background.
Mark words for proofing which you want to avoid in your copy like “actually”, “absolutely”, etc.

Editor
The theme files are written in JSON. If you miss one comma anywhere, it won’t load. The easiest way to reduce such time-wasting errors is to use an editor which supports JSON. For example “Sublime”. It will show you if you have missed anything:

image.png

Share your theme
Once you have created your own custom theme, please share it with other users/

🔗 Reddit Forum:
→ Share themes
→ Ask questions

🔗 GitHub repo with themes:
→ Download themes
→ Submit themes to the repo with a pull request or reach out on Reddit

⬇️ Full example theme with strikethrough and custom style for ::highlighting::
ayu-mirage-tweaked.json
4.6 kB

Share
 
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.