diff --git a/frappe/desk/doctype/custom_html_block/__init__.py b/frappe/desk/doctype/custom_html_block/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/frappe/desk/doctype/custom_html_block/custom_html_block.js b/frappe/desk/doctype/custom_html_block/custom_html_block.js
new file mode 100644
index 00000000000..727a73c92f2
--- /dev/null
+++ b/frappe/desk/doctype/custom_html_block/custom_html_block.js
@@ -0,0 +1,49 @@
+// Copyright (c) 2023, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Custom HTML Block", {
+ refresh(frm) {
+ render_custom_html_block(frm);
+ },
+});
+
+function render_custom_html_block(frm) {
+ let wrapper = frm.fields_dict["preview"].wrapper;
+ wrapper.classList.add("mb-3");
+
+ let random_id = "custom-block-" + frappe.utils.get_random(5).toLowerCase();
+
+ class CustomBlock extends HTMLElement {
+ constructor() {
+ super();
+
+ // html
+ let div = document.createElement("div");
+ div.innerHTML = frappe.dom.remove_script_and_style(frm.doc.html);
+
+ // css
+ let style = document.createElement("style");
+ style.textContent = frm.doc.style;
+
+ // javascript
+ let script = document.createElement("script");
+ script.textContent = `
+ (function() {
+ let cname = ${JSON.stringify(random_id)};
+ let root_element = document.querySelector(cname).shadowRoot;
+ ${frm.doc.script}
+ })();
+ `;
+
+ this.attachShadow({ mode: "open" });
+ this.shadowRoot?.appendChild(div);
+ this.shadowRoot?.appendChild(style);
+ this.shadowRoot?.appendChild(script);
+ }
+ }
+
+ if (!customElements.get(random_id)) {
+ customElements.define(random_id, CustomBlock);
+ }
+ wrapper.innerHTML = `<${random_id}>${random_id}>`;
+}
diff --git a/frappe/desk/doctype/custom_html_block/custom_html_block.json b/frappe/desk/doctype/custom_html_block/custom_html_block.json
new file mode 100644
index 00000000000..b730b557018
--- /dev/null
+++ b/frappe/desk/doctype/custom_html_block/custom_html_block.json
@@ -0,0 +1,125 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "prompt",
+ "creation": "2023-05-17 13:58:37.311045",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "preview_section",
+ "preview",
+ "html_section",
+ "html",
+ "javascript_section",
+ "script",
+ "css_section",
+ "style"
+ ],
+ "fields": [
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:true;",
+ "fieldname": "html_section",
+ "fieldtype": "Section Break",
+ "label": "HTML"
+ },
+ {
+ "fieldname": "html",
+ "fieldtype": "Code",
+ "options": "HTML"
+ },
+ {
+ "fieldname": "preview_section",
+ "fieldtype": "Section Break",
+ "label": "Preview"
+ },
+ {
+ "fieldname": "preview",
+ "fieldtype": "HTML"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:true;",
+ "fieldname": "javascript_section",
+ "fieldtype": "Section Break",
+ "label": "Javascript"
+ },
+ {
+ "fieldname": "script",
+ "fieldtype": "Code",
+ "options": "JS"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:true;",
+ "fieldname": "css_section",
+ "fieldtype": "Section Break",
+ "label": "CSS"
+ },
+ {
+ "fieldname": "style",
+ "fieldtype": "Code",
+ "options": "CSS"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2023-05-17 14:11:57.890253",
+ "modified_by": "Administrator",
+ "module": "Desk",
+ "name": "Custom HTML Block",
+ "naming_rule": "Set by user",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Workspace Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/frappe/desk/doctype/custom_html_block/custom_html_block.py b/frappe/desk/doctype/custom_html_block/custom_html_block.py
new file mode 100644
index 00000000000..7f85c2db5fe
--- /dev/null
+++ b/frappe/desk/doctype/custom_html_block/custom_html_block.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class CustomHTMLBlock(Document):
+ pass
diff --git a/frappe/desk/doctype/custom_html_block/test_custom_html_block.py b/frappe/desk/doctype/custom_html_block/test_custom_html_block.py
new file mode 100644
index 00000000000..fbef9af45b9
--- /dev/null
+++ b/frappe/desk/doctype/custom_html_block/test_custom_html_block.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestCustomHTMLBlock(FrappeTestCase):
+ pass