Customising Frappe ERPNext UI: Part I — Adding a new theme

Pratheesh Russell
5 min readJun 17, 2024

Frappe is a powerful open-source web framework designed for building rich, data-centric web applications. It is built on Python and JavaScript, offering a flexible and scalable architecture that enables developers to create complex applications with ease. One of the most prominent applications built on Frappe is ERPNext, a comprehensive enterprise resource planning (ERP) system. Frappe’s modular design allows developers to extend and customise applications without modifying the core code, ensuring maintainability and upgradeability.

you can find the installation steps for Frappe framework in this link

In this series, we will explore various ways to customise the UI of Frappe Desk through practical examples. Our focus will be on enhancing functionality and aesthetics without altering the core framework files by leveraging custom apps. FrappeJS exposes a lot of its functionality through the frappe object, which can be hooked into at runtime using JS, to implement custom behaviours and modifications.

In this article we will create out first custom app and add a new theme

Creating an app in Frappe

To create a new app you just have to run the command

bench new-app modern_desk

This should create a modern_desk folder. Next step is to add the modern_desk app to our site.

bench --site [site name] install-app modern_desk

Now when you run the app and browse to your site link, you should be able to see that the modern_desk app has been added

The Modern Desk app is present under Installed apps when you click the about link

The benefit of creating a separate app and not modifying core files is that, You can push this app to GitHub and install it with just a single command after setting up frappe.

Adding a new theme

Before adding a new Theme lets understand how themes work in Frappe. Frappe comes with a two themes installed so let’s see what happens when we change them.

When we change the theme frappe adds data-theme=”THEME-NAME” to the html element. We can target this data attribute when we write our css

[data-theme=modern_ui_theme]{
--primary: var(--main-color);
--dt-primary-color: var(--main-color);
--blue-avatar-bg: var(--main-color);
--blue-avatar-color: var(--main-color);
--blue: var(--main-color)
}

You can find a collection of themes in this repo, sundae_theme

Add your theme css to public/css folder

Next task is to add our theme to Frappe’s theme switcher. This is defined in the ThemeSwitcher class

All we need to do is override the fetch_themes method. And this is simple because this particular class is exposed by the frappe object.

frappe.ui.ThemeSwitcher = class CustomThemeSwitcher extends frappe.ui.ThemeSwitcher {
constructor() {
super()
}

fetch_themes() {
return new Promise((resolve) => {
this.themes = [
{
name: "light",
label: ("Frappe Light"),
info: ("Light Theme"),
},
{
name: "dark",
label: "Timeless Night",
info: "Dark Theme",
},
{
name: "modern_ui_theme",
label: "Modern Desk UI",
info: "A modern theme, copied from github"
},
{
name: "automatic",
label: "Automatic",
info: "Uses system's theme to switch between light and dark mode",
}
];

resolve(this.themes);
});
}
}

In the above code we are simply extending the class and overriding the method. Simple right? This is how we can customise a lot of the UI in frappe.

Now we have our style as well as the JS. Next we need to add them to hooks.py so that frappe will know that it has to load these

In hooks.py file, add our file paths under app_include css and js sections. This will be injected globally.

And now when you run the app you can see your theme is loaded in the theme switcher and that you are able to switch theme colours this way

We are almost done but if you notice that, even though the theme gets switched, if we reload the page it goes back to light theme. This is because frappe does a hard-coded check before saving the current theme name to db

To override it just add python file in our app, add that function with our theme name

overrides/switch_theme.py

In hooks.py under override_whitelisted_methods add

override_whitelisted_methods = {
"frappe.core.doctype.user.user.switch_theme": "modern_desk.overrides.switch_theme.switch_theme"
}

we are overriding the switch_theme in frappe core with the switch_theme in modern_desk app (folder path separated with dot). And that is it, now the theme switcher should work properly without any issues

In this first part of our series on customising the Frappe ERPNext UI, we walked through the initial steps of creating a custom app and adding a new theme. This foundational knowledge sets the stage for more advanced customisation, allowing us to tailor the look and feel of Frappe Desk to better suit our needs.

By leveraging the modular design of Frappe and the power of the frappe object, we’ve demonstrated how you can enhance your application’s aesthetics without altering the core framework files. As we continue to explore Frappe’s capabilities, remember that customization doesn’t stop at themes. In upcoming articles, we’ll delve into more complex modifications.

Thank you for joining me. If you have any questions or need further assistance, feel free to reach out. Let’s continue building and customising together!

--

--

Pratheesh Russell

I am a software developer worked with technologies like Flutter, Angular and NestJS.