diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js
index 162dd6771..373fedf48 100644
--- a/resources/js/components/markdown-editor.js
+++ b/resources/js/components/markdown-editor.js
@@ -26,7 +26,8 @@ export class MarkdownEditor extends Component {
             text: {
                 serverUploadLimit: this.serverUploadLimitText,
                 imageUploadError: this.imageUploadErrorText,
-            }
+            },
+            settings: this.loadSettings(),
         }).then(editor => {
             this.editor = editor;
             this.setupListeners();
@@ -81,7 +82,7 @@ export class MarkdownEditor extends Component {
             const name = actualInput.getAttribute('name');
             const value = actualInput.getAttribute('value');
             window.$http.patch('/preferences/update-boolean', {name, value});
-            // TODO - Update state locally
+            this.editor.settings.set(name, value === 'true');
         });
 
         // Refresh CodeMirror on container resize
@@ -90,6 +91,17 @@ export class MarkdownEditor extends Component {
         observer.observe(this.elem);
     }
 
+    loadSettings() {
+        const settings = {};
+        const inputs = this.settingContainer.querySelectorAll('input[type="hidden"]');
+
+        for (const input of inputs) {
+            settings[input.getAttribute('name')] = input.value === 'true';
+        }
+
+        return settings;
+    }
+
     scrollToTextIfNeeded() {
         const queryParams = (new URL(window.location)).searchParams;
         const scrollText = queryParams.get('content-text');
diff --git a/resources/js/markdown/codemirror.js b/resources/js/markdown/codemirror.js
index 06860b929..8724a23c8 100644
--- a/resources/js/markdown/codemirror.js
+++ b/resources/js/markdown/codemirror.js
@@ -24,7 +24,13 @@ export async function init(editor) {
 
     // Handle scroll to sync display view
     const onScrollDebounced = debounce(editor.actions.syncDisplayPosition.bind(editor.actions), 100, false);
-    cm.on('scroll', instance => onScrollDebounced(instance));
+    let syncActive = editor.settings.get('scrollSync');
+    editor.settings.onChange('scrollSync', val => syncActive = val);
+    cm.on('scroll', instance => {
+        if (syncActive) {
+            onScrollDebounced(instance);
+        }
+    });
 
     // Handle image paste
     cm.on('paste', (cm, event) => {
diff --git a/resources/js/markdown/display.js b/resources/js/markdown/display.js
index 7e1925431..2c78da189 100644
--- a/resources/js/markdown/display.js
+++ b/resources/js/markdown/display.js
@@ -17,6 +17,14 @@ export class Display {
         } else {
             this.container.addEventListener('load', this.onLoad.bind(this));
         }
+
+        this.updateVisibility(editor.settings.get('showPreview'));
+        editor.settings.onChange('showPreview', show => this.updateVisibility(show));
+    }
+
+    updateVisibility(show) {
+        const wrap = this.container.closest('.markdown-editor-wrap');
+        wrap.style.display = show ? null : 'none';
     }
 
     onLoad() {
diff --git a/resources/js/markdown/editor.js b/resources/js/markdown/editor.js
index decebe5f4..f2e34b9f0 100644
--- a/resources/js/markdown/editor.js
+++ b/resources/js/markdown/editor.js
@@ -1,6 +1,7 @@
 import {Markdown} from "./markdown";
 import {Display} from "./display";
 import {Actions} from "./actions";
+import {Settings} from "./settings";
 import {listen} from "./common-events";
 import {init as initCodemirror} from "./codemirror";
 
@@ -18,6 +19,7 @@ export async function init(config) {
     const editor = {
         config,
         markdown: new Markdown(),
+        settings: new Settings(config.settings),
     };
 
     editor.actions = new Actions(editor);
@@ -38,6 +40,7 @@ export async function init(config) {
  * @property {HTMLTextAreaElement} inputEl
  * @property {String} drawioUrl
  * @property {Object<String, String>} text
+ * @property {Object<String, any>} settings
  */
 
 /**
@@ -47,4 +50,5 @@ export async function init(config) {
  * @property {Markdown} markdown
  * @property {Actions} actions
  * @property {CodeMirror} cm
+ * @property {Settings} settings
  */
\ No newline at end of file
diff --git a/resources/js/markdown/settings.js b/resources/js/markdown/settings.js
new file mode 100644
index 000000000..6dd142210
--- /dev/null
+++ b/resources/js/markdown/settings.js
@@ -0,0 +1,40 @@
+import {kebabToCamel} from "../services/text";
+
+
+export class Settings {
+
+    constructor(initialSettings) {
+        this.settingMap = {};
+        this.changeListeners = {};
+        this.merge(initialSettings);
+    }
+
+    set(key, value) {
+        key = this.normaliseKey(key);
+        this.settingMap[key] = value;
+        for (const listener of (this.changeListeners[key] || [])) {
+            listener(value);
+        }
+    }
+
+    get(key) {
+        return this.settingMap[this.normaliseKey(key)] || null;
+    }
+
+    merge(settings) {
+        for (const [key, value] of Object.entries(settings)) {
+            this.set(key, value);
+        }
+    }
+
+    onChange(key, callback) {
+        key = this.normaliseKey(key);
+        const listeners = this.changeListeners[this.normaliseKey(key)] || [];
+        listeners.push(callback);
+        this.changeListeners[this.normaliseKey(key)] = listeners;
+    }
+
+    normaliseKey(key) {
+        return kebabToCamel(key.replace('md-', ''));
+    }
+}
\ No newline at end of file
diff --git a/resources/js/services/components.js b/resources/js/services/components.js
index 7434f6430..d1503db4d 100644
--- a/resources/js/services/components.js
+++ b/resources/js/services/components.js
@@ -1,3 +1,5 @@
+import {kebabToCamel, camelToKebab} from "./text";
+
 /**
  * A mapping of active components keyed by name, with values being arrays of component
  * instances since there can be multiple components of the same type.
@@ -107,17 +109,6 @@ function parseOpts(name, element) {
     return opts;
 }
 
-/**
- * Convert a kebab-case string to camelCase
- * @param {String} kebab
- * @returns {string}
- */
-function kebabToCamel(kebab) {
-    const ucFirst = (word) => word.slice(0,1).toUpperCase() + word.slice(1);
-    const words = kebab.split('-');
-    return words[0] + words.slice(1).map(ucFirst).join('');
-}
-
 /**
  * Initialize all components found within the given element.
  * @param {Element|Document} parentElement
@@ -171,8 +162,4 @@ export function get(name) {
 export function firstOnElement(element, name) {
     const elComponents = elementComponentMap.get(element) || {};
     return elComponents[name] || null;
-}
-
-function camelToKebab(camelStr) {
-    return camelStr.replace(/[A-Z]/g, (str, offset) =>  (offset > 0 ? '-' : '') + str.toLowerCase());
 }
\ No newline at end of file
diff --git a/resources/js/services/text.js b/resources/js/services/text.js
new file mode 100644
index 000000000..ea82f993e
--- /dev/null
+++ b/resources/js/services/text.js
@@ -0,0 +1,19 @@
+/**
+ * Convert a kebab-case string to camelCase
+ * @param {String} kebab
+ * @returns {string}
+ */
+export function kebabToCamel(kebab) {
+    const ucFirst = (word) => word.slice(0,1).toUpperCase() + word.slice(1);
+    const words = kebab.split('-');
+    return words[0] + words.slice(1).map(ucFirst).join('');
+}
+
+/**
+ * Convert a camelCase string to a kebab-case string.
+ * @param {String} camelStr
+ * @returns {String}
+ */
+export function camelToKebab(camelStr) {
+    return camelStr.replace(/[A-Z]/g, (str, offset) =>  (offset > 0 ? '-' : '') + str.toLowerCase());
+}
\ No newline at end of file
diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php
index 978e67464..fa2586f8d 100644
--- a/resources/lang/en/entities.php
+++ b/resources/lang/en/entities.php
@@ -224,6 +224,8 @@ return [
     'pages_md_insert_image' => 'Insert Image',
     'pages_md_insert_link' => 'Insert Entity Link',
     'pages_md_insert_drawing' => 'Insert Drawing',
+    'pages_md_show_preview' => 'Show preview',
+    'pages_md_sync_scroll' => 'Sync preview scroll',
     'pages_not_in_chapter' => 'Page is not in a chapter',
     'pages_move' => 'Move Page',
     'pages_move_success' => 'Page moved to ":parentName"',
diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss
index 7d92d0aa0..e4331a03f 100644
--- a/resources/sass/_forms.scss
+++ b/resources/sass/_forms.scss
@@ -80,7 +80,6 @@
   border-bottom: 1px solid #DDD;
   @include lightDark(border-color, #ddd, #000);
   width: 50%;
-  max-width: 50%;
 }
 
 .markdown-editor-wrap + .markdown-editor-wrap {
@@ -97,12 +96,6 @@
     max-width: 100%;
     flex-grow: 1;
   }
-  #markdown-editor .editor-toolbar {
-    padding: 0;
-  }
-  #markdown-editor .editor-toolbar > * {
-    padding: $-xs $-s;
-  }
   .editor-toolbar-label {
     float: none !important;
     @include lightDark(border-color, #DDD, #555);
diff --git a/resources/views/pages/parts/markdown-editor.blade.php b/resources/views/pages/parts/markdown-editor.blade.php
index 41ee3933f..f90a2f54c 100644
--- a/resources/views/pages/parts/markdown-editor.blade.php
+++ b/resources/views/pages/parts/markdown-editor.blade.php
@@ -20,11 +20,11 @@
                 <button refs="dropdown@toggle" class="text-button" type="button" title="{{ trans('common.more') }}">@icon('more')</button>
                 <div refs="dropdown@menu markdown-editor@setting-container" class="dropdown-menu" role="menu">
                     <div class="px-m">
-                        @include('form.toggle-switch', ['name' => 'md-show-preview', 'label' => 'Show preview', 'value' => setting()->getForCurrentUser('md-show-preview')])
+                        @include('form.toggle-switch', ['name' => 'md-show-preview', 'label' => trans('entities.pages_md_show_preview'), 'value' => setting()->getForCurrentUser('md-show-preview')])
                     </div>
                     <hr class="m-none">
                     <div class="px-m">
-                        @include('form.toggle-switch', ['name' => 'md-scroll-sync', 'label' => 'Sync preview scroll', 'value' => setting()->getForCurrentUser('md-scroll-sync')])
+                        @include('form.toggle-switch', ['name' => 'md-scroll-sync', 'label' => trans('entities.pages_md_sync_scroll'), 'value' => setting()->getForCurrentUser('md-scroll-sync')])
                     </div>
                 </div>
             </div>
@@ -40,7 +40,7 @@
 
     </div>
 
-    <div class="markdown-editor-wrap">
+    <div class="markdown-editor-wrap" @if(!setting()->getForCurrentUser('md-show-preview')) style="display: none;" @endif>
         <div class="editor-toolbar">
             <div class="editor-toolbar-label text-mono px-m py-xs">{{ trans('entities.pages_md_preview') }}</div>
         </div>