diff --git a/resources/js/code.mjs b/resources/js/code.mjs
index 8e2ed72c8..537b0d108 100644
--- a/resources/js/code.mjs
+++ b/resources/js/code.mjs
@@ -242,6 +242,21 @@ export function popupEditor(elem, modeSuggestion) {
     });
 }
 
+/**
+ * Create an inline editor to replace the given textarea.
+ * @param {HTMLTextAreaElement} textArea
+ * @param {String} mode
+ * @returns {CodeMirror3}
+ */
+export function inlineEditor(textArea, mode) {
+    return CodeMirror.fromTextArea(textArea, {
+        mode: getMode(mode, textArea.value),
+        lineNumbers: true,
+        lineWrapping: false,
+        theme: getTheme(),
+    });
+}
+
 /**
  * Set the mode of a codemirror instance.
  * @param cmInstance
diff --git a/resources/js/components/code-textarea.js b/resources/js/components/code-textarea.js
new file mode 100644
index 000000000..988e51f19
--- /dev/null
+++ b/resources/js/components/code-textarea.js
@@ -0,0 +1,16 @@
+/**
+ * A simple component to render a code editor within the textarea
+ * this exists upon.
+ * @extends {Component}
+ */
+class CodeTextarea {
+
+    async setup() {
+        const mode = this.$opts.mode;
+        const Code = await window.importVersioned('code');
+        Code.inlineEditor(this.$el, mode);
+    }
+
+}
+
+export default CodeTextarea;
\ No newline at end of file
diff --git a/resources/js/components/index.js b/resources/js/components/index.js
index 6a4a8c2b0..1bbca864c 100644
--- a/resources/js/components/index.js
+++ b/resources/js/components/index.js
@@ -9,6 +9,7 @@ import bookSort from "./book-sort.js"
 import chapterToggle from "./chapter-toggle.js"
 import codeEditor from "./code-editor.js"
 import codeHighlighter from "./code-highlighter.js"
+import codeTextarea from "./code-textarea.js"
 import collapsible from "./collapsible.js"
 import confirmDialog from "./confirm-dialog"
 import customCheckbox from "./custom-checkbox.js"
@@ -65,6 +66,7 @@ const componentMapping = {
     "chapter-toggle": chapterToggle,
     "code-editor": codeEditor,
     "code-highlighter": codeHighlighter,
+    "code-textarea": codeTextarea,
     "collapsible": collapsible,
     "confirm-dialog": confirmDialog,
     "custom-checkbox": customCheckbox,
diff --git a/resources/views/settings/customization.blade.php b/resources/views/settings/customization.blade.php
index b7be95b4a..a7392196b 100644
--- a/resources/views/settings/customization.blade.php
+++ b/resources/views/settings/customization.blade.php
@@ -119,7 +119,13 @@
             <div>
                 <label for="setting-app-custom-head" class="setting-list-label">{{ trans('settings.app_custom_html') }}</label>
                 <p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
-                <textarea name="setting-app-custom-head" id="setting-app-custom-head" class="simple-code-input mt-m">{{ setting('app-custom-head', '') }}</textarea>
+                <div class="mt-m">
+                    <textarea component="code-textarea"
+                              option:code-textarea:mode="html"
+                              name="setting-app-custom-head"
+                              id="setting-app-custom-head"
+                              class="simple-code-input">{{ setting('app-custom-head', '') }}</textarea>
+                </div>
                 <p class="small text-right">{{ trans('settings.app_custom_html_disabled_notice') }}</p>
             </div>