diff --git a/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js b/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js
index 3ab43be5d7223f9d2dd62669708a58971eab104c..a86e501b5d9d688af87897c4d0cef6b05dba6435 100644
--- a/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js
+++ b/addons/web_editor/static/lib/odoo-editor/src/commands/commands.js
@@ -354,6 +354,19 @@ export function toggleFormat(editor, format) {
             }
         }
         if (wasCollapsed) {
+            const siblings = [...zws.parentElement.childNodes];
+            if (
+                selectedTextNodes.includes(siblings[0]) &&
+                selectedTextNodes.includes(siblings[siblings.length - 1])
+            ) {
+                zws.parentElement.setAttribute('oe-zws-empty-inline', '');
+            } else {
+                const span = document.createElement('span');
+                span.setAttribute('oe-zws-empty-inline', '');
+                zws.before(span);
+                span.append(zws);
+
+            }
             setSelection(zws, 1);
         } else {
             setSelection(anchorNode, anchorOffset, focusNode, focusOffset);
@@ -376,6 +389,21 @@ export function toggleFormat(editor, format) {
             } else {
                 el.style[style.name] = style.value;
             }
+            if (zws) {
+                const siblings = [...zws.parentElement.childNodes];
+                if (
+                    selectedTextNodes.includes(siblings[0]) &&
+                    selectedTextNodes.includes(siblings[siblings.length - 1])
+                ) {
+                    zws.parentElement.setAttribute('oe-zws-empty-inline', '');
+                } else {
+                    const span = document.createElement('span');
+                    span.setAttribute('oe-zws-empty-inline', '');
+                    zws.before(span);
+                    span.append(zws);
+
+                }
+            }
         }, format, !isAlreadyFormatted);
     }
 }
diff --git a/addons/web_editor/static/lib/odoo-editor/test/spec/format.test.js b/addons/web_editor/static/lib/odoo-editor/test/spec/format.test.js
index a8a52978e889af7d7851b36273aca71dd5a903c8..5a86afac58dbf531ddc408b6a81caf657fd233de 100644
--- a/addons/web_editor/static/lib/odoo-editor/test/spec/format.test.js
+++ b/addons/web_editor/static/lib/odoo-editor/test/spec/format.test.js
@@ -15,8 +15,8 @@ const strikeThrough = async editor => {
 };
 
 describe('Format', () => {
-    const b = content => `<span style="font-weight: bolder;">${content}</span>`;
-    const notB = (content, weight) => `<span style="font-weight: ${weight || 'normal'};">${content}</span>`;
+    const b = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="font-weight: bolder;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
+    const notB = (content, weight, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="font-weight: ${weight || 'normal'};"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
     describe('bold', () => {
         it('should make a few characters bold', async () => {
             await testEditor(BasicEditor, {
@@ -86,19 +86,21 @@ describe('Format', () => {
             await testEditor(BasicEditor, {
                 contentBefore: '<p>ab[]cd</p>',
                 stepFunction: bold,
-                contentAfter: `<p>ab${b(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${b(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
         it('should get ready to type in not bold', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>${b(`ab[]cd`)}</p>`,
                 stepFunction: bold,
-                contentAfter: `<p>${b(`ab${notB(`[]\u200B`)}cd`)}</p>`,
+                contentAfterEdit: `<p>${b(`ab${notB(`[]\u200B`, undefined, 'first')}cd`)}</p>`,
+                contentAfter: `<p>${b(`ab[]cd`)}</p>`,
             });
         });
     });
-    const i = content => `<span style="font-style: italic;">${content}</span>`;
-    const notI = content => `<span style="font-style: normal;">${content}</span>`;
+    const i = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="font-style: italic;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
+    const notI = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="font-style: normal;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
     describe('italic', () => {
         it('should make a few characters italic', async () => {
             await testEditor(BasicEditor, {
@@ -168,18 +170,20 @@ describe('Format', () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
                 stepFunction: italic,
-                contentAfter: `<p>ab${i(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${i(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
         it('should get ready to type in not italic', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>${i(`ab[]cd`)}</p>`,
                 stepFunction: italic,
-                contentAfter: `<p>${i(`ab${notI(`[]\u200B`)}cd`)}</p>`,
+                contentAfterEdit: `<p>${i(`ab${notI(`[]\u200B`, 'first')}cd`)}</p>`,
+                contentAfter: `<p>${i(`ab[]cd`)}</p>`,
             });
         });
     });
-    const u = content => `<span style="text-decoration-line: underline;">${content}</span>`;
+    const u = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="text-decoration-line: underline;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
     describe('underline', () => {
         it('should make a few characters underline', async () => {
             await testEditor(BasicEditor, {
@@ -248,18 +252,20 @@ describe('Format', () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${u(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
         it('should get ready to type in not underline', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>${u(`ab[]cd`)}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>${u(`ab`)}\u200B[]${u(`cd`)}</p>`,
+                contentAfterEdit: `<p>${u(`ab`)}<span oe-zws-empty-inline="">\u200B[]</span>${u(`cd`)}</p>`,
+                contentAfter: `<p>${u(`ab`)}[]${u(`cd`)}</p>`,
             });
         });
     });
-    const s = content => `<span style="text-decoration-line: line-through;">${content}</span>`;
+    const s = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="text-decoration-line: line-through;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
     describe('strikeThrough', () => {
         it('should make a few characters strikeThrough', async () => {
             await testEditor(BasicEditor, {
@@ -328,14 +334,16 @@ describe('Format', () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
                 stepFunction: strikeThrough,
-                contentAfter: `<p>ab${s(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${s(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
-        it('should get ready to type in not strikeThrough', async () => {
+        it('should get ready to type in not underline', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>${s(`ab[]cd`)}</p>`,
                 stepFunction: strikeThrough,
-                contentAfter: `<p>${s(`ab`)}\u200B[]${s(`cd`)}</p>`,
+                contentAfterEdit: `<p>${s(`ab`)}<span oe-zws-empty-inline="">\u200B[]</span>${s(`cd`)}</p>`,
+                contentAfter: `<p>${s(`ab`)}[]${s(`cd`)}</p>`,
             });
         });
     });
@@ -344,32 +352,37 @@ describe('Format', () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(s(`cd[]ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(s(`cd`))}${s(`\u200b[]`)}${u(s(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(`\u200b[]`, 'last')}${u(s(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(s(`cd`))}[]${u(s(`ef`))}</p>`,
             });
         });
         it('should restore underline after removing it (collapsed, strikeThrough)', async () => {
             await testEditor(BasicEditor, {
-                contentBefore: `<p>ab${u(s(`cd`))}${s(`\u200b[]`)}${u(s(`ef`))}</p>`,
+                contentBefore: `<p>ab${u(s(`cd`))}${s(`\u200b[]`, 'first')}${u(s(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(s(`cd`))}${s(u(`[]\u200b`))}${u(s(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(u(`[]\u200b`, 'first'), 'first')}${u(s(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(s(`cd`))}[]${u(s(`ef`))}</p>`,
             });
         });
         it('should remove underline after restoring it after removing it (collapsed, strikeThrough)', async () => {
             await testEditor(BasicEditor, {
-                contentBefore: `<p>ab${u(s(`cd`))}${s(u(`[]\u200b`))}${u(s(`ef`))}</p>`,
+                contentBefore: `<p>ab${u(s(`cd`))}${s(u(`[]\u200b`, 'first'))}${u(s(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(s(`cd`))}${s(`\u200b[]`)}${u(s(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(`\u200b[]`, 'last')}${u(s(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(s(`cd`))}[]${u(s(`ef`))}</p>`,
             });
         });
         it('should remove underline after restoring it and writing after removing it (collapsed, strikeThrough)', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(s(`cd`))}${s(u(`ghi[]`))}${u(s(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(s(`cd`))}${s(u(`ghi`) + `\u200b[]`)}${u(s(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(u(`ghi`) + `<span oe-zws-empty-inline="">\u200b[]</span>`)}${u(s(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(s(`cd`))}${s(u(`ghi`) + `[]`)}${u(s(`ef`))}</p>`,
             });
         });
         it('should remove underline, write, restore underline, write, remove underline again, write (collapsed, strikeThrough)', async () => {
-            const uselessSpan = u(''); // TODO: clean
+            const uselessSpan = content => `<span>${content}</span>`; // TODO: clean
+            const uselessU = u(''); // TODO: clean
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(s(`cd[]ef`))}</p>`,
                 stepFunction: async editor => {
@@ -380,12 +393,12 @@ describe('Format', () => {
                     await editor.execCommand('underline');
                     await editor.execCommand('insertText', 'C');
                 },
-                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(`A${u(`B`)}C[]${uselessSpan}`)}${u(s(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(s(`cd`))}${s(`A${u(`B`)}${uselessSpan(`C[]`)}${uselessU}`)}${u(s(`ef`))}</p>`,
             });
         });
     });
     describe('underline + italic', () => {
-        const iAndU = content => `<span style="font-style: italic; text-decoration-line: underline;">${content}</span>`;
+        const iAndU = (content, zws) => `<span${zws === 'first' ? ' oe-zws-empty-inline=""' : ''} style="font-style: italic; text-decoration-line: underline;"${zws === 'last' ? ' oe-zws-empty-inline=""' : ''}>${content}</span>`;
         it('should get ready to write in italic and underline', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
@@ -393,7 +406,8 @@ describe('Format', () => {
                     await editor.execCommand('italic');
                     await editor.execCommand('underline');
                 },
-                contentAfter: `<p>ab${iAndU(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${iAndU(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
         it('should get ready to write in italic, after changing one\'s mind about underline', async () => {
@@ -404,7 +418,8 @@ describe('Format', () => {
                     await editor.execCommand('underline');
                     await editor.execCommand('underline');
                 },
-                contentAfter: `<p>ab${i(`\u200B[]`)}cd</p>`,
+                contentAfterEdit: `<p>ab${i(`\u200B[]`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
@@ -413,7 +428,8 @@ describe('Format', () => {
                     await editor.execCommand('italic');
                     await editor.execCommand('underline');
                 },
-                contentAfter: `<p>ab${i(`\u200B[]`)}cd</p>`,
+                contentAfterEdit: `<p>ab${i(`\u200B[]`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab[]cd</p>`,
@@ -422,39 +438,45 @@ describe('Format', () => {
                     await editor.execCommand('underline');
                     await editor.execCommand('italic');
                 },
-                contentAfter: `<p>ab${i(`[]\u200B`)}cd</p>`,
+                contentAfterEdit: `<p>ab${i(`[]\u200B`, 'first')}cd</p>`,
+                contentAfter: `<p>ab[]cd</p>`,
             });
         });
         it('should get ready to write in italic without underline (underline was first)', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(i(`cd[]ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(i(`cd`))}${i(`\u200b[]`)}${u(i(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(i(`cd`))}${i(`\u200b[]`, 'last')}${u(i(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(i(`cd`))}[]${u(i(`ef`))}</p>`,
             });
         });
         it('should restore underline after removing it (collapsed, italic)', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(i(`cd`))}${i(`\u200b[]`)}${u(i(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(i(`cd`))}${iAndU(`[]\u200b`)}${u(i(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(i(`cd`))}${iAndU(`[]\u200b`, 'last')}${u(i(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(i(`cd`))}[]${u(i(`ef`))}</p>`,
             });
         });
         it('should remove underline after restoring it after removing it (collapsed, italic)', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(i(`cd`))}${i(u(`[]\u200b`))}${u(i(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(i(`cd`))}${i(`\u200b[]`)}${u(i(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(i(`cd`))}${i(`\u200b[]`, 'last')}${u(i(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(i(`cd`))}[]${u(i(`ef`))}</p>`,
             });
         });
         it('should remove underline after restoring it and writing after removing it (collapsed, italic)', async () => {
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(i(`cd`))}${i(u(`ghi[]`))}${u(i(`ef`))}</p>`,
                 stepFunction: underline,
-                contentAfter: `<p>ab${u(i(`cd`))}${i(u(`ghi`) + `\u200b[]`)}${u(i(`ef`))}</p>`,
+                contentAfterEdit: `<p>ab${u(i(`cd`))}${i(u(`ghi`) + `<span oe-zws-empty-inline="">\u200b[]</span>`)}${u(i(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(i(`cd`))}${i(u(`ghi`) + `[]`)}${u(i(`ef`))}</p>`,
             });
         });
         it('should remove underline, write, restore underline, write, remove underline again, write (collapsed, italic)', async () => {
-            const uselessSpan = u(''); // TODO: clean
+            const uselessSpan = content => `<span>${content}</span>`;
+            const uselessU = u(''); // TODO: clean
             await testEditor(BasicEditor, {
                 contentBefore: `<p>ab${u(i(`cd[]ef`))}</p>`,
                 stepFunction: async editor => {
@@ -465,7 +487,7 @@ describe('Format', () => {
                     await editor.execCommand('underline');
                     await editor.execCommand('insertText', 'C');
                 },
-                contentAfterEdit: `<p>ab${u(i(`cd`))}${i(`A${u(`B`)}C[]${uselessSpan}`)}${u(i(`ef`))}</p>`,
+                contentAfter: `<p>ab${u(i(`cd`))}${i(`A${u(`B`)}${uselessSpan(`C[]`)}${uselessU}`)}${u(i(`ef`))}</p>`,
             });
         });
     });