Client Scripts
A Client Script runs JavaScript in the user's browser when a DocType form is open. Use for:
- Show/hide fields based on values
- Compute derived fields client-side
- Add custom action buttons
- Validate input before save
For most use cases, Client Scripts are the right tool — fast, no page reload, immediate feedback.
Creating one
Customize → Client Script → New: pick the DocType, view (Form/List), and paste your JS.
Form events
frappe.ui.form.on("Sales Invoice", {
refresh(frm) {
// Runs every time the form loads/reloads
if (frm.doc.status === "Paid") {
frm.add_custom_button("Print Receipt", () => {
window.open(`/api/method/erpnext.print_receipt?invoice=${frm.doc.name}`);
});
}
},
customer(frm) {
// Triggers when the customer field changes
frappe.msgprint(`Selected: ${frm.doc.customer}`);
},
validate(frm) {
// Runs before save
if (frm.doc.grand_total > 100000) {
frappe.throw("Invoices over 100k require manager approval");
}
}
});
Child table events
frappe.ui.form.on("Sales Invoice Item", {
qty(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "amount", row.qty * row.rate);
}
});
Calling the server
frappe.call({
method: "myapp.api.check_credit_limit",
args: { customer: frm.doc.customer, amount: frm.doc.grand_total },
callback: (r) => {
if (!r.message.ok) frappe.throw("Over credit limit");
}
});
Limits
- Runs in the user's browser — never trust input here for security. Always re-validate on server in a Server Script or whitelisted method.
- Errors fail silently unless you check the browser console. Add
console.error()while iterating.
For server-side enforcement, see Server Scripts.
Last updated 3 days ago
Was this helpful?