diff --git a/core/views/editor_helpers.py b/core/views/editor_helpers.py
index 1fe30b0..f85d582 100644
--- a/core/views/editor_helpers.py
+++ b/core/views/editor_helpers.py
@@ -130,3 +130,6 @@ class NewWebImageForm(forms.Form):
             if full_path.exists():
                 raise forms.ValidationError("File already exists in %s" % rel_path)
         return self.cleaned_data['file_']
+        
+class HTMLarea(forms.Textarea):
+    template_name = "widgets/HTMLarea.html"
diff --git a/core/views/expo.py b/core/views/expo.py
index 91919a5..d84aa5f 100644
--- a/core/views/expo.py
+++ b/core/views/expo.py
@@ -23,6 +23,8 @@ import troggle.settings as settings
 
 from troggle.lib import version_control
 
+from troggle.core.views.editor_helpers import HTMLarea
+
 
 '''Formerly a separate package called 'flatpages' written by Martin Green 2011. 
 This was NOT django.contrib.flatpages which stores HTML in the database, so the name was changed to expopages.
@@ -380,5 +382,5 @@ class ExpoPageForm(forms.Form):
     '''The form used by the editexpopage function
     '''
     title = forms.CharField(widget=forms.TextInput(attrs={'size':'60', 'placeholder': "Enter title (displayed in tab)"}))
-    html = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":20, 'placeholder': "Enter page content (using HTML)"}))
+    html = forms.CharField(widget=HTMLarea(attrs={"cols":80, "rows":20, 'placeholder': "Enter page content (using HTML)"}))
     change_message = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":3, 'placeholder': "Descibe the change made (for git)"}))
diff --git a/settings.py b/settings.py
index 7c05550..bcb972e 100644
--- a/settings.py
+++ b/settings.py
@@ -134,10 +134,13 @@ INSTALLED_APPS = (
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.admindocs',
+    'django.forms', #Required to customise widget templates
 #    'django.contrib.staticfiles', # We put our CSS etc explicitly in the right place so do not need this
     'troggle.core',
 )
 
+FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' #Required to customise widget templates
+
 # See the recommended order of these in https://docs.djangoproject.com/en/2.2/ref/middleware/
 # Note that this is a radically different onion architecture from earlier versions though it looks the same, 
 # see https://docs.djangoproject.com/en/2.0/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware 
diff --git a/templates/editexpopage.html b/templates/editexpopage.html
index b71c91f..22c9106 100644
--- a/templates/editexpopage.html
+++ b/templates/editexpopage.html
@@ -2,243 +2,14 @@
 {% block title %}Edit {{ path }}{% endblock %}
 {% block extrahead %}
 
-<!--<script src="{{ settings.TINY_MCE_MEDIA_URL }}tiny_mce.js" type="text/javascript"></script>-->
-<!-- <script type="text/javascript"> tinyMCE.init({ mode : "textareas"  }); </script>-->
-
-<script src="{{ settings.MEDIA_URL }}admin/js/vendor/jquery/jquery.js" type="text/javascript"></script>
-
-    <script src={{ settings.MEDIA_URL }}codemirror/codemirror.js></script>
-    <script src={{ settings.MEDIA_URL }}codemirror/xml.js></script>
-    <script src={{ settings.MEDIA_URL }}codemirror/javascript.js></script>
-    <script src={{ settings.MEDIA_URL }}codemirror/css.js></script>
-    <script src={{ settings.MEDIA_URL }}codemirror/htmlmixed.js></script>
-    <link rel=stylesheet href={{ settings.MEDIA_URL }}codemirror/codemirror.css>
-    <link rel=stylesheet href={{ settings.MEDIA_URL }}codemirror/docs.css>
-    <style type=text/css>
-      .CodeMirror {
-        float: left;
-        width: 50%;
-        border: 1px solid black;
-        height: 80%;
-      }
-      .CodeMirror-scroll{
-        height: 99%
-      }
-      iframe {
-        width: 49%;
-        height: 80%;
-        float: left;
-        border: 1px solid black;
-        border-left: 0px;
-      }
-      body{max-width: none;
-           margin-left: 275px;
-           margin-right: 50px;
-           text-align: left;
-           }
-      #id_change_message{
-      height: 5%;
-      }
-    </style>
-    <style type=text/css>
-	html {
-	  font-family: "Helvetica Neue", sans-serif;
-	  width: 100%;
-	  color: #666666;
-	  text-align: center;
-	}
-
-	.popup-overlay {
-	  /*Hides pop-up when there is no "active" class*/
-	  visibility: hidden;
-	  position: absolute;
-	  background: #ffffff;
-	  border: 3px solid #666666;
-	  width: 90%;
-	  height: 80%;
-	  overflow: scroll; 
-	  left: 5%;
-	  z-index: 20;
-	}
-
-	.popup-overlay.active {
-	  /*displays pop-up when "active" class is present*/
-	  visibility: visible;
-	  text-align: center;
-	}
-
-	.popup-content {
-	  /*Hides pop-up content when there is no "active" class */
-	  visibility: hidden;
-	}
-
-	.popup-content.active {
-	  /*Shows pop-up content when "active" class is present */
-	  visibility: visible;
-	}
-
-	button {
-	  display: inline-block;
-	  vertical-align: middle;
-	  border-radius: 30px;
-	  margin: .20rem;
-	  font-size: 1rem;
-	  color: #666666;
-	  background: #ffffff;
-	  border: 1px solid #666666;
-	}
-
-	button:hover {
-	  border: 1px solid #666666;
-	  background: #666666;
-	  color: #ffffff;
-	}
-	</style>
 {% endblock %}
 {% block body %}
 <h1>Edit {{ path }}</h1>
-<!--Creates the add image popup-->
-<div class="add-image-popup popup-overlay">
-  <div class="add-image-popup popup-content">
-    <h2>Select Image</h2>
-    <p id="image_popup_content"> Loading ...</p>
-    <button onclick="new_image_popup()">Upload Image</button> 
-    <button class="close" onclick="$('.add-image-popup').removeClass('active');">Close</button> 
-  </div>
-</div>
-
-<!--Creates the new image popup-->
-<div class="new-image-popup popup-overlay">
-  <div class="new-image-popup popup-content">
-    <h2>New Image</h2>
-    <p id="new_image_popup_content"> Loading ...</p>
-    <button class="close" onclick="$('.new-image-popup').removeClass('active');">Close</button> 
-  </div>
-</div>
 
 <form action="" method="post">{% csrf_token %}
-{{ form.non_field_errors }}
-<div class="fieldWrapper">
-    {{ form.title.errors }}
-    <label for="{{ form.title.id_for_label }}">Title:</label>
-    {{ form.title }}
-</div>
-<div class="fieldWrapper">
-    {{ form.html.errors }}
-    <!--<label for="{{ form.title.id_for_label }}">HTML:</label> -->
-    {{ form.html }}<iframe id=preview></iframe>
-</div>
-<button type="button" onclick="addTag('i', '')">italic</button> 
-<button type="button" onclick="addTag('b', '')">bold</button> 
-<button type="button" onclick="addTag('h2', 'id=&quot;tophead&quot;')">top heading</button> 
-<button type="button" onclick="addTag('h1', '')">heading 1</button> 
-<button type="button" onclick="addTag('h2', '')">heading 2</button> 
-<button type="button" onclick="addTag('h3', '')">heading 3</button> 
-<button type="button" onclick="addTag('h4', '')">heading 4</button> 
-<button type="button" onclick="addTag('a', 'href=&quot;&quot;')">hyperlink</button> 
-<button type="button" onclick="addTag('p', '')">paragraph</button> 
-<button type="button" onclick="add_image_popup()">image</button> 
-<div class="fieldWrapper">
-    {{ form.change_message.errors }}
-    <label for="{{ form.title.id_for_label }}">Git change message:</label>
-    {{ form.change_message }}
-</div>
-{% include "menu.html" %}
+{{ form.as_p }}
 <p><input type="submit" value="Submit" /></p>
 </form>
-
-
-<script>
-
-
-function add_image_popup() {
-  $('.add-image-popup').addClass('active'); 
-  $('#image_popup_content').load("{% url 'image_selector' path %}", function() {
-      $('.thumbnail').click(function(){
-           $(".add-image-popup").removeClass("active");
-           addStr($( this ).attr("data-html"))
-           });
-    })
-  }
-function new_image_popup() {
-  $('.add-image-popup').removeClass('active');
-  $('.new-image-popup').addClass('active');
-  $.ajax({
-          type : "GET", 
-          dataType: "json",
-          url: "{% url 'new_image_form' path %}",
-          success: function(data){handle_new_image(data)}
-          });  
-  }
-  
-function handle_new_image(data) {
-  if (data.hasOwnProperty('form')) {
-      $('#new_image_popup_content').html(data.form);
-      $('#new_image_form').on('submit', function(e){
-         e.preventDefault();
-         data = $('#new_image_form').serialize();
-         
-         $.ajax({
-                type : "POST", 
-                dataType: "json",
-                url: "{% url 'new_image_form' path %}",
-                data: new FormData($('#new_image_form')[0]),     
-                processData: false,
-                contentType: false,
-                success: function(data){
-                   handle_new_image(data);
-                }
-            });
-         });
-    }
-  else if (data.hasOwnProperty('html')) {
-    $('.new-image-popup').removeClass('active');
-    addStr(data.html);
-    }
-  else {
-    alert(data.error);
-    }
-  }
-</script>
-    <script>
-      var delay;
-      // Initialize CodeMirror editor with a nice html5 canvas demo.
-      var editor = CodeMirror.fromTextArea(document.getElementById('id_html'), {
-        mode: 'text/html',
-        tabMode: 'indent',
-        onChange: function() {
-          clearTimeout(delay);
-          delay = setTimeout(updatePreview, 300);
-        }
-      });
-      
-      function updatePreview() {
-        var previewFrame = document.getElementById('preview');
-        var preview =  previewFrame.contentDocument ||  previewFrame.contentWindow.document;
-        preview.open();
-        preview.write("<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><link rel='stylesheet' type='text/css' href='/css/main2.css' />    <style type=text/css>body{max-width: none;margin-left: 15px;margin-right: 15px;}</style></head><body>");
-        preview.write(editor.getValue());
-        preview.write("</body></html>");
-        preview.close();
-      }
-      setTimeout(updatePreview, 300);
-      
-      function addTag(tag, attr){
-          // For codemirror & center cursor
-          var from = editor.getCursor(true);
-          var to = editor.getCursor(false);
-          editor.replaceRange("</"+tag+">", to);
-          if (attr.length > 0) {attr = " " + attr;}
-          editor.replaceRange("<"+tag+attr+">", from);
-          editor.focus();
-          editor.setCursor({line: to.line , ch : to.ch + 2 + tag.length + attr.length });
-      }
-      
-      function addStr(x){
-          var to = editor.getCursor(false);
-          editor.replaceRange(x, to);
-          editor.focus();
-          editor.setCursor({line: to.line , ch : to.ch + x.length });
-      }
-    </script>
+{% include "menu.html" %}
+{% include 'html_editor_scripts_css.html' %}
 {% endblock %}
diff --git a/templates/html_editor_scripts_css.html b/templates/html_editor_scripts_css.html
new file mode 100644
index 0000000..5bd56d4
--- /dev/null
+++ b/templates/html_editor_scripts_css.html
@@ -0,0 +1,166 @@
+<script src="{{ settings.MEDIA_URL }}admin/js/vendor/jquery/jquery.js" type="text/javascript"></script>
+
+    <script src={{ settings.MEDIA_URL }}codemirror/codemirror.js></script>
+    <script src={{ settings.MEDIA_URL }}codemirror/xml.js></script>
+    <script src={{ settings.MEDIA_URL }}codemirror/javascript.js></script>
+    <script src={{ settings.MEDIA_URL }}codemirror/css.js></script>
+    <script src={{ settings.MEDIA_URL }}codemirror/htmlmixed.js></script>
+    <link rel=stylesheet href={{ settings.MEDIA_URL }}codemirror/codemirror.css>
+    <link rel=stylesheet href={{ settings.MEDIA_URL }}codemirror/docs.css>
+    <style type=text/css>
+      .CodeMirror {
+        float: left;
+        width: 50%;
+        border: 1px solid black;
+        height: 80%;
+      }
+      .CodeMirror-scroll{
+        height: 99%
+      }
+      iframe {
+        width: 49%;
+        height: 80%;
+        float: left;
+        border: 1px solid black;
+        border-left: 0px;
+      }
+      body{max-width: none;
+           margin-left: 275px;
+           margin-right: 50px;
+           text-align: left;
+           }
+      #id_change_message{
+      height: 5%;
+      }
+    </style>
+    <style type=text/css>
+	html {
+	  font-family: "Helvetica Neue", sans-serif;
+	  width: 100%;
+	  color: #666666;
+	  text-align: center;
+	}
+
+	.popup-overlay {
+	  /*Hides pop-up when there is no "active" class*/
+	  visibility: hidden;
+	  position: absolute;
+	  background: #ffffff;
+	  border: 3px solid #666666;
+	  width: 90%;
+	  height: 80%;
+	  overflow: scroll; 
+	  left: 5%;
+	  z-index: 20;
+	}
+
+	.popup-overlay.active {
+	  /*displays pop-up when "active" class is present*/
+	  visibility: visible;
+	  text-align: center;
+	}
+
+	.popup-content {
+	  /*Hides pop-up content when there is no "active" class */
+	  visibility: hidden;
+	}
+
+	.popup-content.active {
+	  /*Shows pop-up content when "active" class is present */
+	  visibility: visible;
+	}
+
+
+	</style>
+<script>
+function add_image_popup() {
+  $('.add-image-popup').addClass('active'); 
+  $('#image_popup_content').load("{% url 'image_selector' path %}", function() {
+      $('.thumbnail').click(function(){
+           $(".add-image-popup").removeClass("active");
+           addStr($( this ).attr("data-html"))
+           });
+    })
+  }
+function new_image_popup() {
+  $('.add-image-popup').removeClass('active');
+  $('.new-image-popup').addClass('active');
+  $.ajax({
+          type : "GET", 
+          dataType: "json",
+          url: "{% url 'new_image_form' path %}",
+          success: function(data){handle_new_image(data)}
+          });  
+  }
+  
+function handle_new_image(data) {
+  if (data.hasOwnProperty('form')) {
+      $('#new_image_popup_content').html(data.form);
+      $('#new_image_form').on('submit', function(e){
+         e.preventDefault();
+         data = $('#new_image_form').serialize();
+         
+         $.ajax({
+                type : "POST", 
+                dataType: "json",
+                url: "{% url 'new_image_form' path %}",
+                data: new FormData($('#new_image_form')[0]),     
+                processData: false,
+                contentType: false,
+                success: function(data){
+                   handle_new_image(data);
+                }
+            });
+         });
+    }
+  else if (data.hasOwnProperty('html')) {
+    $('.new-image-popup').removeClass('active');
+    addStr(data.html);
+    }
+  else {
+    alert(data.error);
+    }
+  }
+</script>
+    <script>
+      var delay;
+      // Initialize CodeMirror editor with a nice html5 canvas demo.
+      var editor = CodeMirror.fromTextArea(document.getElementById('id_html'), {
+        mode: 'text/html',
+        tabMode: 'indent',
+        onChange: function() {
+          clearTimeout(delay);
+          delay = setTimeout(updatePreview, 300);
+        }
+      });
+      
+      function updatePreview() {
+        var previewFrame = document.getElementById('preview');
+        var preview =  previewFrame.contentDocument ||  previewFrame.contentWindow.document;
+        preview.open();
+        preview.write("<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><link rel='stylesheet' type='text/css' href='/css/main2.css' />    <style type=text/css>body{max-width: none;margin-left: 15px;margin-right: 15px;}</style></head><body>");
+        preview.write(editor.getValue());
+        preview.write("</body></html>");
+        preview.close();
+      }
+      setTimeout(updatePreview, 300);
+      
+      function addTag(tag, attr){
+          // For codemirror & center cursor
+          var from = editor.getCursor(true);
+          var to = editor.getCursor(false);
+          editor.replaceRange("</"+tag+">", to);
+          if (attr.length > 0) {attr = " " + attr;}
+          editor.replaceRange("<"+tag+attr+">", from);
+          editor.focus();
+          editor.setCursor({line: to.line , ch : to.ch + 2 + tag.length + attr.length });
+      }
+      
+      function addStr(x){
+          var to = editor.getCursor(false);
+          editor.replaceRange(x, to);
+          editor.focus();
+          editor.setCursor({line: to.line , ch : to.ch + x.length });
+      }
+    </script>
+
diff --git a/templates/widgets/HTMLarea.html b/templates/widgets/HTMLarea.html
new file mode 100644
index 0000000..9837327
--- /dev/null
+++ b/templates/widgets/HTMLarea.html
@@ -0,0 +1,32 @@
+<!--Creates the add image popup-->
+<div><div class="add-image-popup popup-overlay">
+  <div class="add-image-popup popup-content">
+    <h2>Select Image</h2>
+    <p id="image_popup_content"> Loading ...</p>
+    <button onclick="new_image_popup()">Upload Image</button> 
+    <button class="close" onclick="$('.add-image-popup').removeClass('active');">Close</button> 
+  </div>
+</div>
+
+<!--Creates the new image popup-->
+<div class="new-image-popup popup-overlay">
+  <div class="new-image-popup popup-content">
+    <h2>New Image</h2>
+    <p id="new_image_popup_content"> Loading ...</p>
+    <button class="close" onclick="$('.new-image-popup').removeClass('active');">Close</button> 
+  </div>
+</div>
+{% include "django/forms/widgets/textarea.html" %}
+<iframe id=preview></iframe>
+<button type="button" onclick="addTag('i', '')">italic</button> 
+<button type="button" onclick="addTag('b', '')">bold</button> 
+<button type="button" onclick="addTag('h2', 'id=&quot;tophead&quot;')">top heading</button> 
+<button type="button" onclick="addTag('h1', '')">heading 1</button> 
+<button type="button" onclick="addTag('h2', '')">heading 2</button> 
+<button type="button" onclick="addTag('h3', '')">heading 3</button> 
+<button type="button" onclick="addTag('h4', '')">heading 4</button> 
+<button type="button" onclick="addTag('a', 'href=&quot;&quot;')">hyperlink</button> 
+<button type="button" onclick="addTag('p', '')">paragraph</button> 
+<button type="button" onclick="add_image_popup()">image</button> 
+<button type="button" onclick="addStr('<hr/>')">horizontal line</button> 
+</div>