Skip to content

devlpr-nitish/frappe-theme

Repository files navigation

Frappe Theme

Real-time, point-and-click UI theming for Frappe Desk — no CSS overrides, no restarts.

License: MIT Frappe Compatible Python pre-commit


Overview

Frappe Theme is an open-source Frappe app that gives System Managers a single, GUI-driven settings page to fully brand the Frappe Desk interface. Pick colors with a color-picker, toggle layout options with checkboxes, set a custom logo and app name, and watch every open browser tab update instantly — no page reload, no bench build, no CSS file to maintain.

Built on top of Frappe's real-time WebSocket infrastructure, changes propagate to all connected sessions the moment you hit Save.


Features

Category What you can control
Sidebar colors Background, icon-area background, text & sub-text colors
Active item Gradient start / end colors, box-shadow
Sidebar branding Custom logo image, app title, and app subtitle in the sidebar header
Brand palette Primary & secondary colors + hover states (exported as CSS variables)
Text Primary, inverse, muted colors
Title area Breadcrumb and page-title bar text/icon color (via text_primary)
Surfaces & borders Canvas, surface, muted backgrounds; default border color
Typography Font size preset: Small (16 px) / Medium (20 px) / Large (24 px)
Layout Hide left sidebar, right sidebar, form footer, and desktop search bar independently
Search bar Hide .desktop-search-wrapper and .navbar-search-bar; block Ctrl+K / Ctrl+G shortcuts globally
Form toolbar Inject Print / Assign To / Attachments / Share buttons when the right sidebar is hidden
Real-time sync All open sessions update instantly — toggle values are carried directly in the WebSocket payload, zero extra AJAX round-trip

Sidebar & Layout Control

You can independently hide the left sidebar, right sidebar, form footer, and desktop search bar from the Sidebar → Layout section of Theme Settings.

Hiding the Desktop Search Bar

Tick Hide Search Bar to:

  1. Suppress the search wrapper elements (.desktop-search-wrapper and .navbar-search-bar) via a persistent CSS rule active on every desk page.
  2. Override DesktopPage.prototype.setup_awesomebar so the Awesomebar is never initialised on the home page — preventing any flash of the bar before CSS takes effect.
  3. Block the Ctrl+K and Ctrl+G keyboard shortcuts globally (capture-phase window listener that fires before Frappe's own handlers on all routes).

All three layers are removed the instant you untick the checkbox and save — no page reload needed.

Moving action buttons to the top navbar

When the right sidebar is hidden, the standard action buttons (Assign, Attachments, Share, etc.) become inaccessible. Frappe Theme solves this by letting you move any combination of those buttons into the form's top navbar — so users never lose access to them.

Enable Hide Right Sidebar, then tick which buttons should appear in the navbar:

Button What it does
Print Opens the print dialog for the current document
Assign To Opens the Assign To dialog
Attachments Opens the Attachments dialog
Share Opens the Share dialog

The buttons appear automatically on every form the moment you save — no page reload needed.


Sidebar Header Branding

The sidebar header (the top block that shows the app logo and name) is fully overridable from Theme Settings → Sidebar → Background section:

Field What it overrides Notes
Left Sidebar App Logo The <img> or SVG icon in .header-logo Upload a file or paste a URL. Supports both Frappe logo variants: an existing <img> tag (src is swapped) and the SVG icon-container (hidden, custom <img> injected). Cleared value restores the original icon.
Left Sidebar App Title .sidebar-item-label.header-title text e.g. your company name
Left Sidebar App Subtitle .sidebar-item-label.header-subtitle text e.g. a tagline or environment name

Changes apply instantly via the WebSocket event; the branding is also re-applied on every SPA route change in case Frappe re-renders the sidebar.


Title Area (Breadcrumbs) Color

Setting a Primary Text color in the Brand & Surfaces tab now also colorises the entire .flex.title-area bar — breadcrumb links, disabled breadcrumb items, page/form title text, the more button, SVG home icon, and the "Not Saved" indicator pill — so the top bar always matches your brand palette.


Screenshots

Theme Settings — Sidebar color configuration Theme Settings Sidebar

Theme Settings — Layout toggles & Navbar button shortcuts

Hide the right sidebar and choose which buttons move to the top navbar. Theme Settings Layout

Themed Frappe Desk in action Themed Desk


Architecture

frappe_theme/
├── hooks.py                          # App entry-point; registers JS assets & boot hook
├── boot.py                           # boot_session hook — overrides app_title / app_logo_url
├── frappe_theme/
│   └── doctype/
│       └── theme_settings/
│           ├── theme_settings.json   # Single DocType — one row, no list view
│           └── theme_settings.py    # on_update → publish_realtime("theme_settings_changed", …)
└── public/
    ├── images/
    │   └── logo.svg                  # Placeholder logo — replace with your own
    └── js/
        ├── theme_desk.js             # Core: CSS injection, layout toggles, sidebar branding,
        │                             #   keyboard blocker, real-time reload (app_include_js)
        ├── desktop.js                # Desktop-page only: DesktopPage prototype patch (page_js)
        └── form_sidebar_buttons.js   # Form toolbar shortcuts when sidebar is hidden

Data flow:

System Manager saves Theme Settings
        │
        ▼
ThemeSettings.on_update()
        │  frappe.publish_realtime("theme_settings_changed", {
        │      hide_left_sidebar, hide_right_sidebar,
        │      hide_form_footer, hide_search_bar,
        │      left_sidebar_app_logo, left_sidebar_app_title,
        │      left_sidebar_app_subtitle
        │  })
        ▼
All browser tabs receive "theme_settings_changed" WebSocket event
        │
        ├─▶ theme_desk.js merges payload into local cache → applies toggles & branding instantly
        │       then reloads full settings in background for sidebar color CSS
        │
        ├─▶ desktop.js merges payload → hides/shows search wrapper
        │
        └─▶ form_sidebar_buttons.js re-injects toolbar buttons

Why two JS files?

File Loaded via Scope
theme_desk.js app_include_js Every desk page — guaranteed to run on any entry route
desktop.js page_js {"desktop": …} Desktop home page only — handles the DesktopPage prototype override which is only meaningful on /app/

The keyboard shortcut blocker (Ctrl+K / Ctrl+G) lives in theme_desk.js (not desktop.js) so it is always registered regardless of which page the user lands on first.

CSS injection strategy

CSS is injected as <style> tags directly into document.head with fixed IDs so they are idempotent — re-injecting a tag replaces its previous content, never duplicates it.

Style tag ID Covers
frappe-theme-sidebar All sidebar + brand + title-area rules
frappe-theme-icons Sidebar SVG icon colors
frappe-theme-font-size Global font-size override
frappe-theme-left-sidebar Toggle: hide left sidebar
frappe-theme-right-sidebar Toggle: hide right sidebar
frappe-theme-form-footer Toggle: hide form footer
frappe-theme-search-bar Toggle: hide search bar

Default brand colors are applied immediately on page load (before the server round-trip) to prevent a flash of unstyled content.


Requirements

  • Frappe / ERPNext v16
  • Python ≥ 3.10
  • Node.js ≥ 18 (for bench build)

Installation

Via bench (recommended)

cd /path/to/your/bench
bench get-app https://github.com/devlpr-nitish/frappe-theme --branch version-16
bench --site <your-site-name> install-app frappe_theme
bench build --app frappe_theme

Verify

Open Frappe Desk → search for "Theme Settings" → the settings form should appear.


Configuration

All configuration lives in Frappe Desk → Theme Settings (search bar or /app/theme-settings). Only users with the System Manager role can modify settings; all other users automatically inherit the active theme.

Sidebar tab

Background & Header Branding

Field Description
Left Sidebar BG Main background of the left navigation panel
Left Sidebar App Title Replaces the app name text in the sidebar header (leave blank to keep Frappe default)
Left Sidebar App Subtitle Replaces the subtitle text in the sidebar header
Left Sidebar Main Icon BG Background behind the app icon at the top of the sidebar
Left Sidebar App Logo Custom logo for the sidebar header — upload or paste URL. Supports both <img> and SVG icon-container variants

Text & Icons

Field Description
Left Sidebar Text Color Primary link / label color
Left Sidebar Subtext Color Secondary / hint text
Left Sidebar Sub Icons Color SVG icon fill color

Active Item

Field Description
Gradient Start / End Active sidebar item gradient (left → right)

Layout

Field Description
Hide Left Sidebar Collapse the left panel globally
Hide Right Sidebar Collapse the form sidebar globally
Hide Form Footer Remove the save/discard bar at the bottom of forms
Hide Search Bar Hide the desktop search bar and block Ctrl+K / Ctrl+G shortcuts on all routes

Show in Navbar (when right sidebar is hidden)

Field Description
Print Show Print button in form top-bar
Assign To Show Assign To button in form top-bar
Attachments Show Attachments button in form top-bar
Share Show Share button in form top-bar

Brand & Surfaces tab

Field Description
Primary / Secondary Brand accent colors (exported as --ft-primary / --ft-secondary CSS vars)
Primary Hover / Secondary Hover Hover-state variants
Primary Text Global text color — also applied to the breadcrumb / title area bar
Inverse Text / Muted Text Inverse and muted text palette
Section Header Accent Color of section-header rule lines inside forms
Canvas / Surface / Muted Background Page and card background layers
Default Border Border color used across the UI
Font Size Global base font size: Small / Medium (default) / Large

Custom Logo

Drop your own SVG (or PNG) at frappe_theme/public/images/logo.svg, then:

bench build --app frappe_theme

Alternatively, upload or paste any URL directly in Theme Settings → Left Sidebar App Logo — no rebuild required for URL-based logos.


Development Setup

# 1. Clone into your bench apps directory
cd /path/to/bench
git clone https://github.com/devlpr-nitish/frappe-theme apps/frappe_theme

# 2. Install the app on your dev site
bench --site <dev-site> install-app frappe_theme
bench build --app frappe_theme

# 3. Enable pre-commit hooks
cd apps/frappe_theme
pip install pre-commit
pre-commit install

# 4. Start the dev server
cd /path/to/bench
bench start

Production Deployment

# Frappe v16 only
bench get-app https://github.com/devlpr-nitish/frappe-theme --branch version-16
bench --site <prod-site> install-app frappe_theme
bench build --app frappe_theme --production
bench restart

Multi-tenant note: Theme Settings is a Single DocType — it is stored per-site, so each site in a multi-tenant bench has its own independent theme.


Upgrading

cd /path/to/bench
bench update --pull
bench --site <site-name> migrate
bench build --app frappe_theme
bench restart

Contributing

Contributions are welcome! Please read CONTRIBUTING.md before opening a pull request.

Quick start:

git clone https://github.com/devlpr-nitish/frappe-theme
cd frappe-theme
pre-commit install

Security

Found a vulnerability? Please do not open a public issue. See SECURITY.md for the responsible disclosure process.


License

MIT © 2026 Nitish Kumar

About

Frappe Theme is an open-source Frappe app, GUI-driven settings page to fully brand the Frappe Desk interface. Pick colors with a color-picker, toggle layout options with checkboxes, and watch every open browser tab update instantly — no page reload, no bench build, no CSS file to maintain.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors