# Theme Development Guide This guide covers creating custom themes for Trilium Notes. Themes allow you to customize the visual appearance of the application to match your preferences or organizational branding. ## Prerequisites - CSS and CSS Variables knowledge - Understanding of color theory and accessibility - Basic knowledge of Trilium's note system - Familiarity with browser developer tools ## Understanding Trilium's Theme System ### Theme Architecture Trilium's theming system uses CSS custom properties (variables) for consistent styling across the application. Themes are stored as CSS code notes that override default variables. ### Default Themes Trilium includes several built-in themes: - **Light** - Default light theme - **Dark** - Dark mode theme - **Steel Blue** - Professional blue theme - **Next** - Modern, clean theme ### CSS Variable Structure Themes work by overriding CSS custom properties defined in the root scope: ```css :root { /* Main colors */ --main-background-color: #ffffff; --main-text-color: #333333; --main-border-color: #dddddd; /* Accent colors */ --primary-color: #007bff; --secondary-color: #6c757d; /* Component colors */ --button-background-color: #f0f0f0; --button-text-color: #333333; /* And many more... */ } ``` ## Creating Your First Theme ### Step 1: Create Theme Note 1. Create a new code note 2. Set type to "CSS" 3. Add label `#appTheme=myThemeName` 4. Add label `#appCss` (for global application) ### Step 2: Define Basic Colors ```css /* My Custom Theme */ :root { /* Primary Palette */ --theme-primary: #5e72e4; --theme-secondary: #825ee4; --theme-success: #2dce89; --theme-info: #11cdef; --theme-warning: #fb6340; --theme-danger: #f5365c; /* Neutral Colors */ --theme-white: #ffffff; --theme-light: #f6f9fc; --theme-gray: #8898aa; --theme-dark: #32325d; --theme-black: #000000; /* Main Application Colors */ --main-background-color: var(--theme-light); --main-text-color: var(--theme-dark); --main-border-color: #e9ecef; /* Primary Actions */ --primary-color: var(--theme-primary); --primary-color-hover: #4c63d2; --primary-text-color: var(--theme-white); /* Menu and Navigation */ --menu-background-color: var(--theme-white); --menu-text-color: var(--theme-dark); --menu-hover-background-color: var(--theme-light); /* Tree Component */ --tree-background-color: var(--theme-white); --tree-text-color: var(--theme-dark); --tree-hover-background-color: #f0f4f8; --tree-selected-background-color: var(--theme-primary); --tree-selected-text-color: var(--theme-white); /* Editor */ --editor-background-color: var(--theme-white); --editor-text-color: var(--theme-dark); --editor-selection-background: rgba(94, 114, 228, 0.2); /* Buttons */ --button-background-color: var(--theme-white); --button-text-color: var(--theme-dark); --button-border-color: var(--main-border-color); --button-hover-background-color: var(--theme-light); /* Inputs */ --input-background-color: var(--theme-white); --input-text-color: var(--theme-dark); --input-border-color: #cbd5e0; --input-focus-border-color: var(--theme-primary); /* Code */ --code-background-color: #f7fafc; --code-text-color: #d63384; /* Links */ --link-color: var(--theme-primary); --link-hover-color: var(--theme-secondary); /* Shadows */ --box-shadow-sm: 0 1px 3px rgba(50, 50, 93, 0.15); --box-shadow-md: 0 4px 6px rgba(50, 50, 93, 0.11); --box-shadow-lg: 0 10px 40px rgba(50, 50, 93, 0.2); } ``` ### Step 3: Style Components ```css /* Component Customizations */ /* Note Tree Styling */ .tree-wrapper { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 1px; } .tree { background: var(--tree-background-color); border-radius: 8px; margin: 1px; } .fancytree-node { border-radius: 4px; margin: 2px 4px; transition: all 0.2s ease; } .fancytree-node:hover { transform: translateX(2px); box-shadow: var(--box-shadow-sm); } /* Tab Styling */ .note-tab { background: var(--theme-white); border: none; border-radius: 8px 8px 0 0; margin-right: 2px; transition: all 0.2s ease; } .note-tab:hover { background: var(--theme-light); transform: translateY(-2px); } .note-tab.active { background: var(--theme-primary); color: var(--theme-white); box-shadow: var(--box-shadow-md); } /* Button Styling */ .btn { border-radius: 6px; padding: 8px 16px; font-weight: 500; transition: all 0.2s ease; border: 1px solid transparent; } .btn:hover { transform: translateY(-1px); box-shadow: var(--box-shadow-md); } .btn-primary { background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%); color: var(--theme-white); border: none; } /* Card/Panel Styling */ .card { border: none; border-radius: 12px; box-shadow: var(--box-shadow-sm); overflow: hidden; } .card-header { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); border-bottom: 2px solid var(--main-border-color); padding: 12px 16px; } /* Dialog Styling */ .modal-content { border-radius: 12px; border: none; box-shadow: var(--box-shadow-lg); } .modal-header { background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%); color: var(--theme-white); border-radius: 12px 12px 0 0; } /* Scrollbar Styling */ ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: var(--theme-light); border-radius: 10px; } ::-webkit-scrollbar-thumb { background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%); border-radius: 10px; } ::-webkit-scrollbar-thumb:hover { background: var(--theme-secondary); } ``` ## Complete Theme Example: Modern Dark Here's a complete example of a modern dark theme: ```css /* Modern Dark Theme for Trilium */ :root { /* Color Palette */ --md-bg-primary: #0f0f23; --md-bg-secondary: #1a1b3a; --md-bg-tertiary: #252647; --md-bg-elevated: #2d2f54; --md-text-primary: #e4e4e7; --md-text-secondary: #a1a1aa; --md-text-muted: #71717a; --md-accent-primary: #7c3aed; --md-accent-secondary: #a855f7; --md-accent-success: #10b981; --md-accent-warning: #f59e0b; --md-accent-danger: #ef4444; --md-accent-info: #3b82f6; --md-border: rgba(255, 255, 255, 0.1); --md-border-strong: rgba(255, 255, 255, 0.2); /* Main Application */ --main-background-color: var(--md-bg-primary); --main-text-color: var(--md-text-primary); --main-border-color: var(--md-border); --body-background-color: var(--md-bg-primary); /* Accents */ --primary-color: var(--md-accent-primary); --primary-color-hover: var(--md-accent-secondary); --primary-text-color: #ffffff; --muted-text-color: var(--md-text-muted); --active-item-background-color: var(--md-bg-elevated); --active-item-text-color: var(--md-accent-primary); /* Menu */ --menu-background-color: var(--md-bg-secondary); --menu-text-color: var(--md-text-primary); --menu-hover-background-color: var(--md-bg-tertiary); --dropdown-background-color: var(--md-bg-tertiary); --dropdown-item-hover-background-color: var(--md-bg-elevated); /* Tree */ --tree-background-color: var(--md-bg-secondary); --tree-text-color: var(--md-text-primary); --tree-hover-background-color: var(--md-bg-tertiary); --tree-selected-background-color: var(--md-accent-primary); --tree-selected-text-color: #ffffff; /* Editor */ --editor-background-color: var(--md-bg-primary); --editor-text-color: var(--md-text-primary); --editor-selection-background: rgba(124, 58, 237, 0.3); /* Note Detail */ --detail-background-color: var(--md-bg-primary); --detail-text-color: var(--md-text-primary); --accented-background-color: var(--md-bg-secondary); /* Buttons */ --button-background-color: var(--md-bg-tertiary); --button-text-color: var(--md-text-primary); --button-border-color: var(--md-border); --button-hover-background-color: var(--md-bg-elevated); --button-disabled-background-color: var(--md-bg-secondary); /* Inputs */ --input-background-color: var(--md-bg-secondary); --input-text-color: var(--md-text-primary); --input-border-color: var(--md-border); --input-focus-border-color: var(--md-accent-primary); /* Modal */ --modal-background-color: var(--md-bg-secondary); --modal-header-background-color: var(--md-bg-tertiary); --modal-backdrop-color: rgba(0, 0, 0, 0.7); /* Tabs */ --tab-background-color: var(--md-bg-secondary); --tab-hover-background-color: var(--md-bg-tertiary); --tab-active-background-color: var(--md-bg-primary); --tab-active-text-color: var(--md-accent-primary); /* Code */ --code-background-color: var(--md-bg-secondary); --code-text-color: var(--md-accent-info); /* Links */ --link-color: var(--md-accent-info); --link-hover-color: var(--md-accent-primary); /* Tooltips */ --tooltip-background-color: var(--md-bg-elevated); --tooltip-text-color: var(--md-text-primary); /* Scrollbar */ --scrollbar-track-color: var(--md-bg-secondary); --scrollbar-thumb-color: var(--md-bg-elevated); /* Shadows */ --box-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); --box-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4); --box-shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.5); } /* Component Overrides */ /* Smooth transitions */ * { transition: background-color 0.2s ease, color 0.2s ease; } /* Body and main containers */ body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--md-bg-primary); } /* Glass morphism effect for cards */ .card { background: rgba(26, 27, 58, 0.6); backdrop-filter: blur(10px); border: 1px solid var(--md-border); border-radius: 12px; box-shadow: var(--box-shadow-md); } .card-header { background: rgba(37, 38, 71, 0.8); border-bottom: 1px solid var(--md-border-strong); } /* Gradient accents */ .note-tab.active::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, var(--md-accent-primary), var(--md-accent-secondary)); } /* Glow effects for focused elements */ input:focus, textarea:focus, .CodeMirror-focused { outline: none; border-color: var(--md-accent-primary); box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1); } /* Button animations */ .btn { position: relative; overflow: hidden; border-radius: 8px; font-weight: 500; letter-spacing: 0.025em; } .btn::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent); transition: left 0.5s; } .btn:hover::before { left: 100%; } .btn-primary { background: linear-gradient(135deg, var(--md-accent-primary), var(--md-accent-secondary)); border: none; color: white; } /* Tree styling with hover effects */ .fancytree-node { border-radius: 6px; padding: 2px 4px; margin: 2px 8px; } .fancytree-node:hover { background: var(--md-bg-tertiary); box-shadow: inset 0 0 0 1px var(--md-border-strong); } .fancytree-active { background: var(--md-accent-primary) !important; color: white !important; } .fancytree-active .fancytree-title { color: white !important; } /* Note content styling */ .note-detail { padding: 24px; } .note-detail h1 { color: var(--md-accent-primary); border-bottom: 2px solid var(--md-border-strong); padding-bottom: 12px; margin-bottom: 24px; } .note-detail h2 { color: var(--md-accent-secondary); margin-top: 32px; margin-bottom: 16px; } .note-detail code { background: var(--md-bg-tertiary); color: var(--md-accent-info); padding: 2px 6px; border-radius: 4px; font-family: 'JetBrains Mono', 'Fira Code', monospace; } .note-detail pre { background: var(--md-bg-secondary); border: 1px solid var(--md-border); border-radius: 8px; padding: 16px; overflow-x: auto; } .note-detail blockquote { border-left: 4px solid var(--md-accent-primary); background: var(--md-bg-secondary); padding: 12px 20px; margin: 16px 0; border-radius: 0 8px 8px 0; } /* Table styling */ table { border-collapse: separate; border-spacing: 0; border-radius: 8px; overflow: hidden; box-shadow: var(--box-shadow-sm); } th { background: var(--md-bg-tertiary); color: var(--md-accent-primary); font-weight: 600; text-transform: uppercase; font-size: 0.875em; letter-spacing: 0.05em; } td { background: var(--md-bg-secondary); border-top: 1px solid var(--md-border); } tr:hover td { background: var(--md-bg-tertiary); } /* Scrollbar styling */ ::-webkit-scrollbar { width: 12px; height: 12px; } ::-webkit-scrollbar-track { background: var(--md-bg-secondary); border-radius: 6px; } ::-webkit-scrollbar-thumb { background: var(--md-bg-elevated); border-radius: 6px; border: 2px solid var(--md-bg-secondary); } ::-webkit-scrollbar-thumb:hover { background: var(--md-accent-primary); } /* Animations */ @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .modal { animation: fadeIn 0.2s ease; } /* Loading states */ .loading { position: relative; } .loading::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(90deg, transparent, rgba(124, 58, 237, 0.1), transparent ); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } /* Focus visible for accessibility */ *:focus-visible { outline: 2px solid var(--md-accent-primary); outline-offset: 2px; } /* Custom tooltip styling */ .tooltip { background: var(--md-bg-elevated); border: 1px solid var(--md-border-strong); border-radius: 6px; padding: 8px 12px; font-size: 0.875em; box-shadow: var(--box-shadow-lg); } .tooltip-arrow { border-color: var(--md-bg-elevated); } ``` ## Advanced Theming Techniques ### Dynamic Theme Switching ```javascript // Frontend script for theme switching class ThemeSwitcher { constructor() { this.themes = ['light', 'dark', 'modern-dark', 'custom']; this.currentTheme = this.getCurrentTheme(); this.init(); } init() { this.createThemeToggle(); this.bindEvents(); this.applyTheme(this.currentTheme); } createThemeToggle() { const $toggle = $(`