diff --git a/packages/core/src/css/intlTelInput.css b/packages/core/src/css/intlTelInput.css index caab58d39..5b92f4633 100644 --- a/packages/core/src/css/intlTelInput.css +++ b/packages/core/src/css/intlTelInput.css @@ -132,6 +132,32 @@ direction: ltr; } +/* Fork RTL layout: right-align the phone number so it sits next to the country button, which + holds the flag and the separate dial code on the inline-start (right) edge. The number and + dial code then read as one group hugging the flag ("51 234 5678 +966 🇦🇪"). Pure CSS, + scoped to :dir(rtl); the LTR layout is unchanged and the dial code keeps its single, + direction-agnostic position inside the country button (see ui.ts #buildCountryContainer). + + Note: placing a *separate* dial-code element to the LEFT of the right-aligned number, in a + full-width field, is not expressible in pure CSS — it needs the number's pixel width (a JS + measurement) or a field that shrinks to its content. Keeping the dial code by the flag is + the full-width, pure-CSS layout. The scope is keyed off the wrapper's directionality (a + plain
, whose :dir resolves reliably) and reaches the input via a descendant selector, + so it does not depend on the 's own :dir resolution. */ +.iti:dir(rtl) .iti__tel-input { + /* Right-align the number so it sits next to the country button. */ + text-align: right; + /* The input's own direction resolves to LTR (browsers force it for tel/number-style inputs + even inside an RTL page), so its logical inline-start is the physical LEFT — where the + JS-set flag-clearance padding lands, and the WRONG side for an RTL widget whose country + button is on the right. Neutralise that padding and re-apply the clearance on the physical + RIGHT (the input's inline-end). The width comes from the --iti-country-clearance custom + property that ui.ts publishes (a measurement; the side is chosen here in CSS). !important + beats both the JS inline padding-inline-start and any consumer id-selector padding. */ + padding-inline-start: var(--iti-spacer-horizontal) !important; + padding-inline-end: var(--iti-country-clearance, 0px) !important; +} + .iti__arrow { margin-inline-start: var(--iti-arrow-padding); margin-top: -2px; diff --git a/packages/core/src/js/core/ui.ts b/packages/core/src/js/core/ui.ts index 3fbd32447..6fc515138 100644 --- a/packages/core/src/js/core/ui.ts +++ b/packages/core/src/js/core/ui.ts @@ -487,6 +487,15 @@ export default class UI { const inputPadding = selectedCountryWidth + LAYOUT.INPUT_PADDING_EXTRA_LEFT; this.telInputEl.style.paddingInlineStart = `${inputPadding}px`; + //* Publish the clearance width as a custom property so the RTL stylesheet can place it on + //* the physical RIGHT. Browsers resolve a tel input's own direction as LTR even inside an + //* RTL page, so the line above (logical inline-start) writes to the physical LEFT, whereas + //* the flag/country button in an RTL widget sits on the RIGHT. This is a measurement only — + //* the direction/side decision lives entirely in CSS (intlTelInput.css, scoped to :dir(rtl)). + this.telInputEl.style.setProperty( + "--iti-country-clearance", + `${inputPadding}px`, + ); } } diff --git a/tests-e2e/visual.spec.ts-snapshots/vanilla-rtl-dropdown-open-chromium.png b/tests-e2e/visual.spec.ts-snapshots/vanilla-rtl-dropdown-open-chromium.png index 7740ccf92..c3686252c 100644 Binary files a/tests-e2e/visual.spec.ts-snapshots/vanilla-rtl-dropdown-open-chromium.png and b/tests-e2e/visual.spec.ts-snapshots/vanilla-rtl-dropdown-open-chromium.png differ