diff --git a/frappe/printing/doctype/letter_head/letter_head.json b/frappe/printing/doctype/letter_head/letter_head.json
index 119a59120f..f4aa731b86 100644
--- a/frappe/printing/doctype/letter_head/letter_head.json
+++ b/frappe/printing/doctype/letter_head/letter_head.json
@@ -7,29 +7,32 @@
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
- "letter_head_for",
"letter_head_name",
"module",
"source",
"footer_source",
"column_break_3",
+ "letter_head_for",
"standard",
"disabled",
"is_default",
"letter_head_image_section",
+ "align",
"image",
+ "column_break_dpzk",
"image_height",
"image_width",
- "align",
- "header_section",
- "content",
- "footer_section",
- "footer",
"footer_image_section",
+ "footer_align",
"footer_image",
+ "column_break_kfvf",
"footer_image_height",
"footer_image_width",
- "footer_align",
+ "header_section",
+ "content",
+ "custom_css",
+ "footer_section",
+ "footer",
"scripts_section",
"header_script",
"footer_script",
@@ -47,7 +50,6 @@
"unique": 1
},
{
- "depends_on": "letter_head_name",
"fieldname": "source",
"fieldtype": "Select",
"label": "Letter Head Based On",
@@ -59,7 +61,6 @@
},
{
"default": "0",
- "depends_on": "letter_head_name",
"fieldname": "disabled",
"fieldtype": "Check",
"in_list_view": 1,
@@ -69,7 +70,6 @@
},
{
"default": "0",
- "depends_on": "letter_head_name",
"fieldname": "is_default",
"fieldtype": "Check",
"in_list_view": 1,
@@ -79,45 +79,42 @@
"search_index": 1
},
{
- "depends_on": "eval:doc.letter_head_name && doc.source === 'Image'",
+ "depends_on": "eval:doc.source === 'Image'",
"fieldname": "letter_head_image_section",
"fieldtype": "Section Break",
"label": "Letter Head Image"
},
{
- "depends_on": "eval:doc.letter_head_name && doc.source === 'Image'",
"fieldname": "image",
"fieldtype": "Attach Image",
"label": "Image"
},
{
- "depends_on": "eval:doc.source==='HTML' && doc.letter_head_name",
+ "depends_on": "eval:doc.source==='HTML'",
"fieldname": "header_section",
"fieldtype": "Section Break",
"label": "Header"
},
{
- "depends_on": "eval:!doc.__islocal && doc.source==='HTML'",
+ "depends_on": "eval:doc.source==='HTML'",
"description": "Letter Head in HTML",
"fieldname": "content",
"fieldtype": "HTML Editor",
- "ignore_xss_filter": 1,
"label": "Header HTML",
"oldfieldname": "content",
"oldfieldtype": "Text Editor"
},
{
- "depends_on": "eval:doc.footer_source==='HTML' && doc.letter_head_name",
+ "depends_on": "eval:doc.footer_source==='HTML'",
"fieldname": "footer_section",
"fieldtype": "Section Break",
"label": "Footer"
},
{
- "depends_on": "eval:!doc.__islocal",
+ "depends_on": "eval:doc.footer_source==='HTML'",
"description": "Footer will display correctly only in PDF",
"fieldname": "footer",
"fieldtype": "HTML Editor",
- "ignore_xss_filter": 1,
"label": "Footer HTML"
},
{
@@ -138,7 +135,7 @@
"label": "Image Width (px)"
},
{
- "depends_on": "eval:doc.footer_source==='Image' && doc.letter_head_name",
+ "depends_on": "eval:doc.footer_source==='Image'",
"fieldname": "footer_image_section",
"fieldtype": "Section Break",
"label": "Footer Image"
@@ -165,22 +162,20 @@
"options": "Left\nRight\nCenter"
},
{
- "default": "HTML",
- "depends_on": "letter_head_name",
"fieldname": "footer_source",
"fieldtype": "Select",
"label": "Footer Based On",
"options": "Image\nHTML"
},
{
- "depends_on": "eval:!doc.__islocal && doc.source==='HTML'",
+ "depends_on": "eval:doc.source==='HTML'",
"fieldname": "header_script",
"fieldtype": "Code",
"label": "Header Script",
"options": "Javascript"
},
{
- "depends_on": "eval:!doc.__islocal && doc.footer_source==='HTML'",
+ "depends_on": "eval:doc.footer_source==='HTML'",
"fieldname": "footer_script",
"fieldtype": "Code",
"label": "Footer Script",
@@ -188,8 +183,8 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "eval: doc.header_script || doc.footer_script",
- "depends_on": "eval: !doc.__islocal",
+ "collapsible_depends_on": "eval:doc.header_script || doc.footer_script",
+ "depends_on": "eval:doc.source === 'HTML' || doc.footer_source === 'HTML'",
"fieldname": "scripts_section",
"fieldtype": "Section Break",
"label": "Scripts"
@@ -223,6 +218,21 @@
"label": "Module",
"mandatory_depends_on": "eval: doc.standard == \"Yes\"",
"options": "Module Def"
+ },
+ {
+ "fieldname": "column_break_dpzk",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_kfvf",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.source === 'HTML'",
+ "fieldname": "custom_css",
+ "fieldtype": "Code",
+ "label": "Custom CSS",
+ "options": "CSS"
}
],
"icon": "fa fa-font",
@@ -230,7 +240,7 @@
"links": [],
"make_attachments_public": 1,
"max_attachments": 3,
- "modified": "2026-04-08 13:15:24.935222",
+ "modified": "2026-04-24 13:17:34.972069",
"modified_by": "Administrator",
"module": "Printing",
"name": "Letter Head",
diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py
index 220a09cac1..2582b40674 100644
--- a/frappe/printing/doctype/letter_head/letter_head.py
+++ b/frappe/printing/doctype/letter_head/letter_head.py
@@ -19,6 +19,7 @@ class LetterHead(Document):
align: DF.Literal["Left", "Right", "Center"]
content: DF.HTMLEditor | None
+ custom_css: DF.Code | None
disabled: DF.Check
footer: DF.HTMLEditor | None
footer_align: DF.Literal["Left", "Right", "Center"]
@@ -39,11 +40,6 @@ class LetterHead(Document):
standard: DF.Literal["No", "Yes"]
# end: auto-generated types
- def before_insert(self):
- # for better UX, let user set from attachment
- if not frappe.flags.in_migrate and not frappe.flags.in_install:
- self.source = "Image"
-
def on_trash(self):
from frappe.defaults import clear_default
diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py
index 3a3770bce1..62440c3358 100644
--- a/frappe/utils/print_format.py
+++ b/frappe/utils/print_format.py
@@ -294,7 +294,7 @@ def render_letterhead_for_print(letterhead: str | None = None, doc: dict | str |
frappe.db.get_value(
"Letter Head",
letterhead or {"is_default": 1},
- ["content", "footer", "header_script", "footer_script"],
+ ["content", "footer", "header_script", "footer_script", "custom_css"],
as_dict=True,
)
or {}
@@ -305,9 +305,11 @@ def render_letterhead_for_print(letterhead: str | None = None, doc: dict | str |
if letter_head.content:
header = render_template(letter_head.content, {"doc": context_doc})
+ if letter_head.custom_css:
+ header += f"\n\n"
+ rendered["header"] = header
if letter_head.header_script:
header += f"\n\n"
- rendered["header"] = header
if letter_head.footer:
footer = render_template(letter_head.footer, {"doc": context_doc})
diff --git a/frappe/www/printview.py b/frappe/www/printview.py
index ff2b048305..15e9ea1854 100644
--- a/frappe/www/printview.py
+++ b/frappe/www/printview.py
@@ -230,6 +230,12 @@ def get_rendered_template(
if letter_head.content:
letter_head.content = frappe.utils.jinja.render_template(letter_head.content, {"doc": doc.as_dict()})
+ if letter_head.custom_css:
+ letter_head.content += f"""
+
+ """
if letter_head.header_script:
letter_head.content += f"""