Why Frontend Development in Frappe is Different
Unlike frameworks where you build the UI from scratch, Frappe gives you two types of frontends:
- Desk UI (Internal) – Auto-generated interface for managing DocTypes, used by internal users.
- Website UI (External) – Public-facing website and pages, useful for customer portals, landing pages, etc.
With Frappe, you can:
- Customize forms and views inside the Desk
- Build custom Pages and Web Templates
- Use Client Scripts for interactivity
- Pull and push data via REST APIs
1. Desk UI Customization with Client Scripts
Client Scripts are JavaScript snippets attached to a DocType that run in the browser.
Example: Auto-fill due date with today’s date
frappe.ui.form.on("ToDo Plus", {
refresh: function(frm) {
if (!frm.doc.due_date) {
frm.set_value("due_date", frappe.datetime.get_today());
}
}
});
Example: Color status field based on value
frappe.ui.form.on("ToDo Plus", {
status: function(frm) {
let status_colors = {
"Pending": "orange",
"In Progress": "blue",
"Completed": "green",
"Overdue": "red"
};
frm.fields_dict.status.$wrapper.css("color", status_colors[frm.doc.status] || "black");
}
});
2. Custom Pages in Desk
Custom Pages are useful when you want a dashboard or interactive view beyond the standard list view.
Create a Page
bench make-page todo_dashboard --module "ToDo Plus"
Edit JS file (todo_plus/page/todo_dashboard/todo_dashboard.js):
frappe.pages['todo_dashboard'].on_page_load = function(wrapper) {
let page = frappe.ui.make_app_page({
parent: wrapper,
title: 'ToDo Dashboard',
single_column: true
});
frappe.call({
method: "todo_plus.api.get_overdue_tasks",
callback: function(r) {
let html = "<h3>Overdue Tasks</h3><ul>";
r.message.forEach(task => {
html += `<li>${task.title} - Due: ${task.due_date}</li>`;
});
html += "</ul>";
$(wrapper).find('.layout-main').html(html);
}
});
};
This creates a custom dashboard showing overdue tasks.
3. Website Pages & Jinja Templates
Frappe includes a website generator. You can create Web Pages from the Desk or by code.
Example: A public page for tasks
- Go to Desk → Web Page → New
- Title: Tasks
- Content:
{% set tasks = frappe.get_all("ToDo Plus", fields=["title", "due_date", "status"]) %}
<ul>
{% for task in tasks %}
<li>{{ task.title }} - {{ task.status }} - Due: {{ task.due_date }}</li>
{% endfor %}
</ul>
When you visit /tasks, you’ll see your task list.
4. Using REST API in Frontend
You can also use JavaScript to fetch data dynamically.
Example:
fetch('/api/resource/ToDo Plus?fields=["title","due_date"]')
.then(res => res.json())
.then(data => {
console.log(data.data);
});
This allows for live updates without refreshing the page.
5. Styling with Frappe Themes
Frappe uses Bootstrap, so you can:
- Use Bootstrap classes in HTML
- Add custom CSS in /public/css/ folder
- Override templates for advanced customization
Key Learnings from Part 5
- How to customize Desk UI with Client Scripts
- How to build custom Pages for dashboards or tools
- How to use Jinja templates for website pages
- How to call REST APIs from frontend JavaScript
- How to style your app with Bootstrap and custom CSS
What’s Next?
In Part 6, we’ll cover User Permissions & Roles:
- Role-based access control
- Complex permission rules
- Document-level permissions
- Best practices for secure apps