diff --git a/resources/js/wysiwyg/lexical/table/LexicalCaptionNode.ts b/resources/js/wysiwyg/lexical/table/LexicalCaptionNode.ts
index 08c6870e6..d9d83562c 100644
--- a/resources/js/wysiwyg/lexical/table/LexicalCaptionNode.ts
+++ b/resources/js/wysiwyg/lexical/table/LexicalCaptionNode.ts
@@ -1,4 +1,5 @@
 import {
+    $createTextNode,
     DOMConversionMap,
     DOMExportOutput,
     EditorConfig,
@@ -7,6 +8,7 @@ import {
     LexicalNode,
     SerializedElementNode
 } from "lexical";
+import {TableNode} from "@lexical/table/LexicalTableNode";
 
 
 export class CaptionNode extends ElementNode {
@@ -71,4 +73,20 @@ export function $createCaptionNode(): CaptionNode {
 
 export function $isCaptionNode(node: LexicalNode | null | undefined): node is CaptionNode {
     return node instanceof CaptionNode;
+}
+
+export function $tableHasCaption(table: TableNode): boolean {
+    for (const child of table.getChildren()) {
+        if ($isCaptionNode(child)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+export function $addCaptionToTable(table: TableNode, text: string = ''): void {
+    const caption = $createCaptionNode();
+    const textNode = $createTextNode(text || ' ');
+    caption.append(textNode);
+    table.append(caption);
 }
\ No newline at end of file
diff --git a/resources/js/wysiwyg/todo.md b/resources/js/wysiwyg/todo.md
index 695e8cb69..1d42ba3e4 100644
--- a/resources/js/wysiwyg/todo.md
+++ b/resources/js/wysiwyg/todo.md
@@ -10,7 +10,6 @@
 
 ## Secondary Todo
 
-- Table caption text support
 - Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
 - Deep check of translation coverage
 
diff --git a/resources/js/wysiwyg/ui/defaults/forms/tables.ts b/resources/js/wysiwyg/ui/defaults/forms/tables.ts
index b592d7c67..5b484310d 100644
--- a/resources/js/wysiwyg/ui/defaults/forms/tables.ts
+++ b/resources/js/wysiwyg/ui/defaults/forms/tables.ts
@@ -18,6 +18,7 @@ import {formatSizeValue} from "../../../utils/dom";
 import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
 import {CommonBlockAlignment} from "lexical/nodes/common";
 import {colorFieldBuilder} from "../../framework/blocks/color-field";
+import {$addCaptionToTable, $isCaptionNode, $tableHasCaption} from "@lexical/table/LexicalCaptionNode";
 
 const borderStyleInput: EditorSelectFormFieldDefinition = {
     label: 'Border style',
@@ -219,6 +220,7 @@ export const rowProperties: EditorFormDefinition = {
 export function $showTablePropertiesForm(table: TableNode, context: EditorUiContext): EditorFormModal {
     const styles = table.getStyles();
     const modalForm = context.manager.createModal('table_properties');
+
     modalForm.show({
         width: styles.get('width') || '',
         height: styles.get('height') || '',
@@ -228,7 +230,7 @@ export function $showTablePropertiesForm(table: TableNode, context: EditorUiCont
         border_style: styles.get('border-style') || '',
         border_color: styles.get('border-color') || '',
         background_color: styles.get('background-color') || '',
-        // caption: '', TODO
+        caption: $tableHasCaption(table) ? 'true' : '',
         align: table.getAlignment(),
     });
     return modalForm;
@@ -265,7 +267,17 @@ export const tableProperties: EditorFormDefinition = {
                 });
             }
 
-            // TODO - cell caption
+            const showCaption = Boolean(formData.get('caption')?.toString() || '');
+            const hasCaption = $tableHasCaption(table);
+            if (showCaption && !hasCaption) {
+                $addCaptionToTable(table, context.translate('Caption'));
+            } else if (!showCaption && hasCaption) {
+                for (const child of table.getChildren()) {
+                    if ($isCaptionNode(child)) {
+                        child.remove();
+                    }
+                }
+            }
         });
         return true;
     },
@@ -299,9 +311,9 @@ export const tableProperties: EditorFormDefinition = {
                         type: 'text',
                     },
                     {
-                        label: 'caption', // Caption element
+                        label: 'Show caption', // Caption element
                         name: 'caption',
-                        type: 'text', // TODO -
+                        type: 'checkbox',
                     },
                     alignmentInput, // alignment class
                 ];
diff --git a/resources/js/wysiwyg/ui/framework/forms.ts b/resources/js/wysiwyg/ui/framework/forms.ts
index 771ab0bdf..08edb214e 100644
--- a/resources/js/wysiwyg/ui/framework/forms.ts
+++ b/resources/js/wysiwyg/ui/framework/forms.ts
@@ -11,7 +11,7 @@ import {el} from "../../utils/dom";
 export interface EditorFormFieldDefinition {
     label: string;
     name: string;
-    type: 'text' | 'select' | 'textarea';
+    type: 'text' | 'select' | 'textarea' | 'checkbox';
 }
 
 export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefinition {
@@ -42,7 +42,11 @@ export class EditorFormField extends EditorUiElement {
 
     setValue(value: string) {
         const input = this.getDOMElement().querySelector('input,select,textarea') as HTMLInputElement;
-        input.value = value;
+        if (this.definition.type === 'checkbox') {
+            input.checked = Boolean(value);
+        } else {
+            input.value = value;
+        }
         input.dispatchEvent(new Event('change'));
     }
 
@@ -61,6 +65,8 @@ export class EditorFormField extends EditorUiElement {
             input = el('select', {id, name: this.definition.name, class: 'editor-form-field-input'}, optionElems);
         } else if (this.definition.type === 'textarea') {
             input = el('textarea', {id, name: this.definition.name, class: 'editor-form-field-input'});
+        } else if (this.definition.type === 'checkbox') {
+            input = el('input', {id, name: this.definition.name, type: 'checkbox', class: 'editor-form-field-input-checkbox', value: 'true'});
         } else {
             input = el('input', {id, name: this.definition.name, class: 'editor-form-field-input'});
         }