Create Custom Themes
Notyra supports customizing themes using JSON files. Users can create their own color themes and fully customize Notyra's appearance to their liking.
Theme File Structure
A theme is a single .json file with the following shape:
{
"id": "my-theme",
"name": "My Theme",
"nameJa": "マイテーマ",
"description": "A short description in English",
"descriptionJa": "日本語での説明",
"swatches": ["#accent", "#background", "#subtle"],
"swatchesDark": ["#accent-dark", "#background-dark", "#subtle-dark"],
"light": {
"--background": "oklch(...)",
"--foreground": "oklch(...)",
"...": "..."
},
"dark": {
"--background": "oklch(...)",
"--foreground": "oklch(...)",
"...": "..."
}
}Top-level Fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier. Use lowercase with hyphens (e.g. "ocean-blue"). |
name | string | Yes | Display name in English. |
nameJa | string | Yes | Display name in Japanese. |
description | string | No | Short description in English. |
descriptionJa | string | No | Short description in Japanese. |
swatches | string[] | Yes | 3 hex colors for the light mode preview chip: [accent, background, subtle]. |
swatchesDark | string[] | Yes | 3 hex colors for the dark mode preview chip: [accent, background, subtle]. |
light | object | Yes | CSS variable map applied in light mode. |
dark | object | Yes | CSS variable map applied in dark mode. |
CSS Variables Reference
All values in light and dark are set on :root via element.style.setProperty(). You can use any valid CSS value — OKLch, hex, rgba(), or references to other vars like var(--foreground).
Base Variables (shadcn/ui compatible)
These follow the shadcn/ui convention and control the overall color palette.
| Variable | Description |
|---|---|
--background | Page / panel background |
--foreground | Default text color |
--card | Card surface background |
--card-foreground | Text on cards |
--popover | Popover / dropdown background |
--popover-foreground | Text in popovers |
--primary | Primary interactive color (buttons, etc.) |
--primary-foreground | Text on primary color |
--secondary | Secondary surface (code blocks, etc.) |
--secondary-foreground | Text on secondary surface |
--muted | Subtle background (tags, badges, muted areas) |
--muted-foreground | Muted / subdued text |
--accent | Hover/focus highlight background |
--accent-foreground | Text on accent background |
--destructive | Destructive action color |
--destructive-foreground | Text on destructive color |
--border | Default border color |
--input | Input field border color |
--ring | Focus ring color |
--radius | Base border radius (e.g. "0.5rem") |
Sidebar Variables
| Variable | Description |
|---|---|
--sidebar | Sidebar panel background |
--sidebar-foreground | Sidebar text |
--sidebar-primary | Sidebar primary color |
--sidebar-primary-foreground | Text on sidebar primary |
--sidebar-accent | Sidebar hover/focus background |
--sidebar-accent-foreground | Text on sidebar accent |
--sidebar-border | Sidebar border color |
--sidebar-ring | Sidebar focus ring |
Chart Variables
--chart-1 through --chart-5 — five colors used for data visualization elements (not commonly needed for basic themes).
Theme-specific Variables
These variables are unique to Notyra and control accent colors throughout the UI — editor headings, active selections, links, badges, and gradient decorations.
| Variable | Description | Example (light) | Example (dark) |
|---|---|---|---|
--theme-accent | Primary accent color. Used for selected items, active icons, heading color (if configured), and interactive highlights. | "#7c3aed" | "#c084fc" |
--theme-accent-hover | Darker variant of the accent for hover states on solid accent backgrounds. | "#6d28d9" | "#e879f9" |
--theme-accent-subtle | Very light tint of the accent. Used for selected item backgrounds, badge backgrounds, and the folder header gradient. Should be near-white in light mode and semi-transparent in dark mode. | "#faf5ff" | "rgba(76, 29, 149, 0.2)" |
--theme-accent-subtle-hover | Slightly stronger version of --theme-accent-subtle for hover states. | "#ede9fe" | "rgba(76, 29, 149, 0.3)" |
--theme-gradient-from | Start color of decorative gradient (app logo lines, etc.). | "#a78bfa" | "#a78bfa" |
--theme-gradient-to | End color of decorative gradient. | "#c084fc" | "#c084fc" |
--theme-link | Hyperlink color in the Markdown preview. | "#8250df" | "#a371f7" |
--theme-link-hover | Link color on hover. | "#a371f7" | "#c084fc" |
--theme-heading-color | Color applied to Markdown headings (h1–h5) in both the editor and preview. Set to "var(--foreground)" for neutral (black/white) headings, or a hex color for accent-colored headings. | "var(--foreground)" | "var(--foreground)" |
Color Format Tips
Notyra uses OKLch for base palette variables and hex / rgba for theme-specific accent variables.
OKLch
OKLch is a perceptually uniform color space: oklch(L C H) where:
- L — lightness (0 = black, 1 = white)
- C — chroma/saturation (0 = gray, higher = more vivid)
- H — hue angle in degrees (0–360)
oklch(0.99 0.006 285) → near-white with a very slight purple tint
oklch(0.13 0.04 285) → near-black with a slight purple tint (dark bg)
oklch(0.45 0.18 250) → medium blue (primary button)Tip: Keep C (chroma) very low for background variables (--background, --card, --sidebar) to achieve a subtle tinted look without being distracting — values like 0.004–0.01 work well.
Hex / rgba
Use hex colors for theme-specific variables (--theme-*) since they need to be vivid and readable:
"--theme-accent": "#059669"
"--theme-accent-subtle": "rgba(5, 150, 105, 0.15)" ← for dark modeHow to Create a Custom Theme
- Copy one of the sample themes as a starting point.
- Change
id,name,nameJa, and optionallydescription/descriptionJa. - Update
swatchesandswatchesDarkwith 3 hex preview colors:[accent, background, subtle]. - Adjust the
--backgroundhue (the third OKLch value,H) to match your chosen color family. Keep chroma (C) around0.004–0.01. - Update the
--theme-*variables to your accent color in bothlightanddarksections. - In Notyra, open Settings → Color Theme → Import and select your JSON file.
Minimal Custom Theme Template
The following template only includes the variables you most likely want to customize. All other variables will fall back to the grayscale defaults.
{
"id": "my-custom-theme",
"name": "My Custom Theme",
"nameJa": "カスタムテーマ",
"description": "My custom color theme",
"descriptionJa": "カスタムカラーテーマ",
"swatches": ["#ACCENT_HEX", "#F9FAFB", "#F0F0FF"],
"swatchesDark": ["#ACCENT_DARK_HEX", "#111118", "#1E1E2E"],
"light": {
"--background": "oklch(0.99 0.006 HUE)",
"--foreground": "oklch(0.13 0 0)",
"--card": "oklch(0.99 0.006 HUE)",
"--card-foreground": "oklch(0.13 0 0)",
"--popover": "oklch(1 0 0)",
"--popover-foreground": "oklch(0.13 0 0)",
"--primary": "oklch(0.45 0.18 HUE)",
"--primary-foreground": "oklch(0.98 0 0)",
"--secondary": "oklch(0.965 0.008 HUE)",
"--secondary-foreground": "oklch(0.2 0 0)",
"--muted": "oklch(0.965 0.008 HUE)",
"--muted-foreground": "oklch(0.5 0 0)",
"--accent": "oklch(0.955 0.01 HUE)",
"--accent-foreground": "oklch(0.18 0 0)",
"--destructive": "oklch(0.577 0.245 27.325)",
"--destructive-foreground": "oklch(0.577 0.245 27.325)",
"--border": "oklch(0.91 0.01 HUE)",
"--input": "oklch(0.91 0.01 HUE)",
"--ring": "oklch(0.55 0.18 HUE)",
"--radius": "0.5rem",
"--sidebar": "oklch(0.975 0.008 HUE)",
"--sidebar-foreground": "oklch(0.13 0 0)",
"--sidebar-primary": "oklch(0.45 0.18 HUE)",
"--sidebar-primary-foreground": "oklch(0.98 0 0)",
"--sidebar-accent": "oklch(0.955 0.01 HUE)",
"--sidebar-accent-foreground": "oklch(0.18 0 0)",
"--sidebar-border": "oklch(0.91 0.01 HUE)",
"--sidebar-ring": "oklch(0.55 0.18 HUE)",
"--theme-accent": "#ACCENT_HEX",
"--theme-accent-hover": "#ACCENT_DARKER_HEX",
"--theme-accent-subtle": "#SUBTLE_HEX",
"--theme-accent-subtle-hover": "#SUBTLE_HOVER_HEX",
"--theme-gradient-from": "#GRADIENT_FROM_HEX",
"--theme-gradient-to": "#GRADIENT_TO_HEX",
"--theme-link": "#LINK_HEX",
"--theme-link-hover": "#LINK_HOVER_HEX",
"--theme-heading-color": "var(--foreground)"
},
"dark": {
"--background": "oklch(0.13 0.04 HUE)",
"--foreground": "oklch(0.94 0 0)",
"--card": "oklch(0.155 0.04 HUE)",
"--card-foreground": "oklch(0.94 0 0)",
"--popover": "oklch(0.13 0.04 HUE)",
"--popover-foreground": "oklch(0.94 0 0)",
"--primary": "oklch(0.65 0.18 HUE)",
"--primary-foreground": "oklch(0.1 0 0)",
"--secondary": "oklch(0.22 0.045 HUE)",
"--secondary-foreground": "oklch(0.94 0 0)",
"--muted": "oklch(0.22 0.045 HUE)",
"--muted-foreground": "oklch(0.62 0 0)",
"--accent": "oklch(0.26 0.05 HUE)",
"--accent-foreground": "oklch(0.94 0 0)",
"--destructive": "oklch(0.396 0.141 25.723)",
"--destructive-foreground": "oklch(0.637 0.237 25.331)",
"--border": "oklch(0.24 0.045 HUE)",
"--input": "oklch(0.24 0.045 HUE)",
"--ring": "oklch(0.55 0.18 HUE)",
"--radius": "0.5rem",
"--sidebar": "oklch(0.17 0.042 HUE)",
"--sidebar-foreground": "oklch(0.94 0 0)",
"--sidebar-primary": "oklch(0.65 0.18 HUE)",
"--sidebar-primary-foreground": "oklch(0.1 0 0)",
"--sidebar-accent": "oklch(0.22 0.045 HUE)",
"--sidebar-accent-foreground": "oklch(0.94 0 0)",
"--sidebar-border": "oklch(0.24 0.045 HUE)",
"--sidebar-ring": "oklch(0.55 0.18 HUE)",
"--theme-accent": "#ACCENT_DARK_HEX",
"--theme-accent-hover": "#ACCENT_DARK_HOVER_HEX",
"--theme-accent-subtle": "rgba(R, G, B, 0.15)",
"--theme-accent-subtle-hover": "rgba(R, G, B, 0.25)",
"--theme-gradient-from": "#GRADIENT_FROM_DARK_HEX",
"--theme-gradient-to": "#GRADIENT_TO_DARK_HEX",
"--theme-link": "#LINK_DARK_HEX",
"--theme-link-hover": "#LINK_DARK_HOVER_HEX",
"--theme-heading-color": "var(--foreground)"
}
}Replace HUE with the OKLch hue angle for your color (e.g. 250 for blue, 160 for green, 55 for amber, 285 for purple).
TypeScript Interface
If you are building tooling around Notyra themes, the theme shape is:
interface ColorTheme {
id: string
name: string
nameJa: string
description?: string
descriptionJa?: string
/** [accent, background, subtle] — hex colors for the light mode preview chip */
swatches: string[]
/** [accent, background, subtle] — hex colors for the dark mode preview chip */
swatchesDark: string[]
/** CSS variable map applied in light mode */
light: Record<string, string>
/** CSS variable map applied in dark mode */
dark: Record<string, string>
}Themes are validated with the following minimum requirements before being imported:
idmust be a non-empty stringnamemust be a non-empty stringswatchesmust be a non-empty arrayswatchesDarkmust be a non-empty arraylightanddarkmust be non-null objects
Usage of Custom Themes
In addition to the default themes, Notyra also offers custom themes that users can utilize. Users can further customize the appearance of Notyra to their liking.
Unsigned App Installation
Notyra is not yet signed. This guide explains how to handle security warnings when installing Notyra.