Skip to main content

Right-to-Left (RTL)

Elements render left-to-right by default. Set direction: 'rtl' at initialization to render them right-to-left for languages such as Arabic and Hebrew.


Enabling RTL

direction is an SDK option, so it applies to every element created from that SDK instance.

import BasisTheory from '@basis-theory/web-elements';

const bt = BasisTheory('<PUBLIC_API_KEY>', {
direction: 'rtl',
});

With React Elements, pass it through the options prop:

import { BasisTheoryProvider } from '@basis-theory/react-elements';

function App() {
return (
<BasisTheoryProvider
apiKey="<PUBLIC_API_KEY>"
options={{ direction: 'rtl' }}
>
<PaymentForm />
</BasisTheoryProvider>
);
}
OptionTypeDefaultDescription
direction'ltr' | 'rtl''ltr'Writing direction applied to every element. Any other value throws a ConfigurationError.
languagestringBCP 47 tag applied to every element. A value that is not a BCP 47 tag throws a ConfigurationError.

What changes inside the elements

With direction: 'rtl':

  • Placeholders and the card brand picker align to the right.
  • In the card element, the expiration date and CVV fields swap position, without you changing layout.
  • The card brand icon and the CVV reveal toggle move to the opposite side of the input.

Your own markup is unaffected. Field labels, headings, and the surrounding form live on your page, outside the element iframes, so set the direction there yourself:

<html lang="ar" dir="rtl">

Card fields stay left-to-right

The card number, expiration date, and CVV fields keep a left-to-right writing direction even when direction is 'rtl'. They are aligned to the right, but their digits are not reordered.

This matters for the card number. A space is a neutral character, and European numbers act as right-to-left when they influence adjacent neutrals (Unicode UAX #9, rule N1). In a right-to-left paragraph the spaces between digit groups therefore resolve to right-to-left, each group becomes its own run, and the runs are laid out right to left. A card number entered as 4111 2222 3333 4444 displays as 4444 3333 2222 4111 while the submitted value stays correct — the shopper reads their own card number back reversed.

The expiration date and CVV do not reorder on their own. 12/25 collapses to a single run because a lone separator between two numbers takes their type (rule W4), and 123 has no separator at all. Elements pins all three fields to left-to-right regardless, so a change to how a value is formatted cannot reintroduce the problem.

If you render card numbers or other grouped digits in your own markup on an RTL page, isolate them with direction: ltr; unicode-bidi: isolate. On an inline element such as a <span>, direction on its own has no effect — it applies only when unicode-bidi is embed, isolate, isolate-override, bidi-override, or plaintext. The same reordering affects masked values that contain spaces or parentheses, such as (555) 123-4567.

Language

Element iframes declare lang="en" until you set language. Pass a BCP 47 tag so assistive technology announces your placeholder and ariaLabel text with the right pronunciation rules:

const bt = BasisTheory('<PUBLIC_API_KEY>', {
direction: 'rtl',
language: 'ar',
});

Set it independently of direction. Right-to-left does not imply Arabic — Hebrew, Persian, and Urdu are also right-to-left — so neither value can be inferred from the other. Set lang on your own markup too, since your labels sit outside the iframes.


Arabic-Indic digits

The card number, expiration date, and CVV fields accept Arabic-Indic (٠-٩, U+0660-U+0669) and extended Arabic-Indic (۰-۹, U+06F0-U+06F9) digits, which a keyboard in an Arabic or Persian locale may produce instead of ASCII.

They are normalized to ASCII as the shopper types, so the field shows the same digits embossed on the card and the tokenized value is unchanged.

This applies to the element's own fields. If you validate or reformat card data in your own code, note that JavaScript's \d matches ASCII digits only — /\p{Nd}/u matches the full set.

Text elements

text elements hold arbitrary values, so each value takes its direction from its own content rather than from the page. An Arabic or Hebrew cardholder name reads right-to-left, while a value with no letters in it — a masked phone number such as (555) 123-4567, for example — renders left-to-right and keeps its groups in order.

You do not need to configure this.


Changing direction

direction is fixed for the life of an element. Passing it to update() has no effect.

To switch direction — for example when a shopper changes language — re-initialize the SDK with the new value and mount the elements again:

cardNumber.unmount();
expiry.unmount();
cvv.unmount();

const bt = BasisTheory('<PUBLIC_API_KEY>', { direction: 'rtl' });