From c4884ee31c2d2d0a7d296b807eb930d420dcfb73 Mon Sep 17 00:00:00 2001 From: Alon Barad <35544532+alon710@users.noreply.github.com> Date: Mon, 26 Oct 2026 10:34:46 +0200 Subject: [PATCH] fix(editor): use logical CSS properties so the editor UI mirrors in RTL The bubble menu, slash command menu, inspector and placeholder styles used physical properties (border-left, padding-right, margin-left, left: 0, text-align: left, float: left). In a right-to-left page these put separators, spacing, menu text and placeholders on the wrong side. They now use the logical equivalents (border-inline-start, padding-inline-end, margin-inline-start, inset-inline-start, text-align: start, float: inline-start), which resolve to the same values in left-to-right layouts. Styles that end up in the exported email HTML are left physical on purpose, since email clients don't support logical properties. Co-Authored-By: Claude Opus 5.5 --- .changeset/editor-logical-css.md | 5 +++++ packages/editor/src/ui/bubble-menu/bubble-menu.css | 8 ++++---- packages/editor/src/ui/inspector/inspector.css | 4 ++-- packages/editor/src/ui/slash-command/slash-command.css | 2 +- packages/editor/src/ui/themes/default.css | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .changeset/editor-logical-css.md diff --git a/.changeset/editor-logical-css.md b/.changeset/editor-logical-css.md new file mode 100644 index 0000000000..1abeab3af6 --- /dev/null +++ b/.changeset/editor-logical-css.md @@ -0,0 +1,5 @@ +--- +"@react-email/editor": patch +--- + +The bubble menu, slash command menu, inspector and placeholder styles now use logical CSS properties, so they mirror correctly when the editor sits in a right-to-left (`dir="rtl"`) page. Left-to-right layouts are unchanged. diff --git a/packages/editor/src/ui/bubble-menu/bubble-menu.css b/packages/editor/src/ui/bubble-menu/bubble-menu.css index 17a24e2944..9a3c5fad83 100644 --- a/packages/editor/src/ui/bubble-menu/bubble-menu.css +++ b/packages/editor/src/ui/bubble-menu/bubble-menu.css @@ -15,13 +15,13 @@ gap: 0.125rem; padding: 0 0.125rem; border: none; - border-left: 1px solid var(--re-border); + border-inline-start: 1px solid var(--re-border); margin: 0; min-width: 0; } [data-re-bubble-menu-group]:last-child { - padding-right: 0; + padding-inline-end: 0; } [data-re-bubble-menu-separator] { @@ -84,7 +84,7 @@ padding: 0.375rem 0.5rem; font-size: 0.8125rem; width: 100%; - text-align: left; + text-align: start; } [data-re-node-selector-item] svg { @@ -118,7 +118,7 @@ gap: 0.25rem; position: absolute; top: 100%; - left: 0; + inset-inline-start: 0; margin-top: 0.25rem; width: max-content; min-width: 16rem; diff --git a/packages/editor/src/ui/inspector/inspector.css b/packages/editor/src/ui/inspector/inspector.css index 7093239912..0e483a96e6 100644 --- a/packages/editor/src/ui/inspector/inspector.css +++ b/packages/editor/src/ui/inspector/inspector.css @@ -39,7 +39,7 @@ [data-re-inspector-unit], [data-re-inspector-color-trigger] { - margin-left: 0.2rem; + margin-inline-start: 0.2rem; width: 1rem; height: 1rem; aspect-ratio: 1 / 2; @@ -102,7 +102,7 @@ } [data-re-inspector-toggle-item] + [data-re-inspector-toggle-item] { - border-left: 1px solid var(--re-border, #e5e5e5); + border-inline-start: 1px solid var(--re-border, #e5e5e5); } [data-re-inspector-toggle-item][data-active] { diff --git a/packages/editor/src/ui/slash-command/slash-command.css b/packages/editor/src/ui/slash-command/slash-command.css index 956e079598..90c8ba82f2 100644 --- a/packages/editor/src/ui/slash-command/slash-command.css +++ b/packages/editor/src/ui/slash-command/slash-command.css @@ -30,7 +30,7 @@ cursor: pointer; font-size: 0.875rem; line-height: 1.25rem; - text-align: left; + text-align: start; } [data-re-slash-command-item] svg { diff --git a/packages/editor/src/ui/themes/default.css b/packages/editor/src/ui/themes/default.css index 7e4959649e..49fc74ecb1 100644 --- a/packages/editor/src/ui/themes/default.css +++ b/packages/editor/src/ui/themes/default.css @@ -400,7 +400,7 @@ .tiptap p.is-empty::before, .tiptap .node-heading.is-empty [data-placeholder]::before { opacity: 0.3; - float: left; + float: inline-start; content: attr(data-placeholder); height: 0; pointer-events: none; @@ -409,7 +409,7 @@ .tiptap .node-placeholder::before { color: var(--re-text-muted); content: attr(data-placeholder); - float: left; + float: inline-start; height: 0; pointer-events: none; }