BidiText
XS · 350B gzip budgetIsolates user-controlled text so a mixed-direction sentence does not reorder around it.
- Category
- Internationalisation
- Budget
- xs, static display primitive
- External runtime
- React / React DOM only
axe fixtureSSR rendersource scanbundle budget
Preview
Live fixtureReply from محمد (3 replies)
Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.
Why this exists
BidiText
العربيةA right-to-left name next to a number pulls the number to the wrong side of it. Here the naive version renders the reply count before the name instead of after. The sentence reads backwards, and only for users with RTL names.
Formatting shortcut
إيان - 42 replies
<span>{name} - {n} replies</span>Install
npx shadcn@latest add https://gear5-ui.vercel.app/r/bidi-text.jsonCopies the source into your project.
New here? Set up Tailwind and import aliases first →Source & props
Edit on GitHub ↗Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.
"use client";
export interface BidiTextProps {
/** Text of unknown or user-controlled direction. */
children: React.ReactNode;
/**
* "auto" lets the browser infer direction from the first strong character —
* the right default for user-generated content whose language you do not
* know at render time.
*/
dir?: "auto" | "ltr" | "rtl";
}
/**
* Isolates text whose direction you do not control.
*
* When an Arabic or Hebrew name is interpolated into an English sentence, the
* Unicode bidirectional algorithm reorders the *surrounding* punctuation too:
* "محمد (3 replies)" can render with the parenthesis and count on the wrong
* side, and the sentence reads as scrambled to everyone. The bug is invisible
* in development in an English locale, and reported constantly by users whose
* names trigger it.
*
* `<bdi>` — bidirectional isolate — scopes the reordering to the untrusted run
* so neighbouring text is unaffected. It is one element, has no styling, and
* is the entire fix.
*
* Wrap any interpolated value you did not author: names, titles, filenames,
* search terms, message bodies.
*/
export function BidiText({ children, dir = "auto" }: BidiTextProps) {
return <bdi dir={dir}>{children}</bdi>;
}
What CI checks
Quality contract- Bundled, minified and gzipped against its tier budget
- Audited by axe in the state previewed above
- Rendered through react-dom/server with no browser globals
- Scanned for network calls, dangerous sinks, and unguarded animation