diff --git a/resources/js/wysiwyg/config.js b/resources/js/wysiwyg/config.js
index 30dc6969d..e5a780d18 100644
--- a/resources/js/wysiwyg/config.js
+++ b/resources/js/wysiwyg/config.js
@@ -14,7 +14,11 @@ import {getPlugin as getAboutPlugin} from './plugins-about';
 import {getPlugin as getDetailsPlugin} from './plugins-details';
 import {getPlugin as getTableAdditionsPlugin} from './plugins-table-additions';
 import {getPlugin as getTasklistPlugin} from './plugins-tasklist';
-import {handleClearFormattingOnTableCells, handleEmbedAlignmentChanges} from './fixes';
+import {
+    handleTableCellRangeEvents,
+    handleEmbedAlignmentChanges,
+    handleTextDirectionCleaning,
+} from './fixes';
 
 const styleFormats = [
     {title: 'Large Header', format: 'h2', preview: 'color: blue;'},
@@ -37,9 +41,9 @@ const styleFormats = [
 ];
 
 const formats = {
-    alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-left'},
-    aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-center'},
-    alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-right'},
+    alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video', classes: 'align-left'},
+    aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video', classes: 'align-center'},
+    alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video', classes: 'align-right'},
     calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
     calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
     calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
@@ -194,7 +198,8 @@ function getSetupCallback(options) {
         });
 
         handleEmbedAlignmentChanges(editor);
-        handleClearFormattingOnTableCells(editor);
+        handleTableCellRangeEvents(editor);
+        handleTextDirectionCleaning(editor);
 
         // Custom handler hook
         window.$events.emitPublic(options.containerElement, 'editor-tinymce::setup', {editor});
diff --git a/resources/js/wysiwyg/fixes.js b/resources/js/wysiwyg/fixes.js
index e51c373d9..7f87d4378 100644
--- a/resources/js/wysiwyg/fixes.js
+++ b/resources/js/wysiwyg/fixes.js
@@ -55,16 +55,30 @@ export function handleEmbedAlignmentChanges(editor) {
 }
 
 /**
- * TinyMCE does not seem to do a great job on clearing styles in complex
- * scenarios (like copied word content) when a range of table cells
- * are selected. This tracks the selected table cells, and watches
- * for clear formatting events, so some manual cleanup can be performed.
- *
+ * Cleans up the direction property for an element.
+ * Removes all inline direction control from child elements.
+ * Removes non "dir" attribute direction control from provided element.
+ * @param {HTMLElement} element
+ */
+function cleanElementDirection(element) {
+    const directionChildren = element.querySelectorAll('[dir],[style*="direction"],[style*="text-align"]');
+    for (const child of directionChildren) {
+        child.removeAttribute('dir');
+        child.style.direction = null;
+        child.style.textAlign = null;
+    }
+    element.style.direction = null;
+    element.style.textAlign = null;
+}
+
+/**
+ * This tracks table cell range selection, so we can apply custom handling where
+ * required to actions applied to such selections.
  * The events used don't seem to be advertised by TinyMCE.
  * Found at https://github.com/tinymce/tinymce/blob/6.8.3/modules/tinymce/src/models/dom/main/ts/table/api/Events.ts
  * @param {Editor} editor
  */
-export function handleClearFormattingOnTableCells(editor) {
+export function handleTableCellRangeEvents(editor) {
     /** @var {HTMLTableCellElement[]} * */
     let selectedCells = [];
 
@@ -75,6 +89,10 @@ export function handleClearFormattingOnTableCells(editor) {
         selectedCells = [];
     });
 
+    // TinyMCE does not seem to do a great job on clearing styles in complex
+    // scenarios (like copied word content) when a range of table cells
+    // are selected. Here we watch for clear formatting events, so some manual
+    // cleanup can be performed.
     const attrsToRemove = ['class', 'style', 'width', 'height'];
     editor.on('FormatRemove', () => {
         for (const cell of selectedCells) {
@@ -83,4 +101,41 @@ export function handleClearFormattingOnTableCells(editor) {
             }
         }
     });
+
+    // TinyMCE does not apply direction events to table cell range selections
+    // so here we hastily patch in that ability by setting the direction ourselves
+    // when a direction event is fired.
+    editor.on('ExecCommand', event => {
+        const command = event.command;
+        if (command !== 'mceDirectionLTR' && command !== 'mceDirectionRTL') {
+            return;
+        }
+
+        const dir = command === 'mceDirectionLTR' ? 'ltr' : 'rtl';
+        for (const cell of selectedCells) {
+            cell.setAttribute('dir', dir);
+            cleanElementDirection(cell);
+        }
+    });
+}
+
+/**
+ * Direction control might not work if there are other unexpected direction-handling styles
+ * or attributes involved nearby. This watches for direction change events to clean
+ * up direction controls, removing non-dir-attr direction controls, while removing
+ * directions from child elements that may be involved.
+ * @param {Editor} editor
+ */
+export function handleTextDirectionCleaning(editor) {
+    editor.on('ExecCommand', event => {
+        const command = event.command;
+        if (command !== 'mceDirectionLTR' && command !== 'mceDirectionRTL') {
+            return;
+        }
+
+        const blocks = editor.selection.getSelectedBlocks();
+        for (const block of blocks) {
+            cleanElementDirection(block);
+        }
+    });
 }