Skip to content

Why an AI Chatbot's RTL Layout Breaks on Long URLs

9 min read · updated August 11, 2026

A model cites a source in the middle of an Arabic answer and the link renders in pieces: the scheme in one place, a path segment somewhere else, the trailing full stop absorbed into the link text. The URL is intact in the data. What broke is that a URL is not one directional run — it is several, separated by characters that have no direction at all.

What splitting looks like

The reported symptoms are worth distinguishing because two of them are layout and two are text.

  • The URL overflows the bubble or forces the container wider than the viewport. Pure CSS: a URL contains no spaces and therefore no break opportunities.
  • The URL wraps in the middle and the second half appears above or to the wrong side of the first. Line breaking interacting with direction: the two fragments are laid out per line, and in an RTL paragraph the second fragment goes to the left of the line below rather than continuing where your eye expects.
  • Part of the URL has moved within the line. Genuine reordering, and the interesting case.
  • A trailing full stop or closing bracket is inside the link, or has moved to the far end of the sentence.

A URL is a mixed-direction string

Take the URL apart by bidi class. https, example, com and any ASCII path segment are class L, strong left-to-right. Digits are EN. But the connective tissue is all weak or neutral: the colon and the solidus are class CS, common separator; the full stop is CS; the question mark, ampersand, equals sign, hash and hyphen are ON or ES. Almost every character that gives a URL its shape has no direction of its own.

In a left-to-right paragraph none of this matters, because N2 resolves every one of those neutrals to the paragraph direction, which is the same as the direction of the strong text around them. In a right-to-left paragraph they resolve to right-to-left instead, so the URL becomes a series of left-to-right islands joined by right-to-left glue — and the islands are then laid out in right-to-left order relative to one another. The same mechanism that reverses date field groups in why numbers look reversed, applied to a longer string with more separators.

Whether you see it depends on the URL. A short, all-ASCII URL usually survives because rules W1 through W7 quietly absorb the separators between adjacent L runs before the neutral rules ever see them. Add a query string, a percent-encoded segment, or a fragment identifier and you add more places for a neutral run to sit between things that are not both L.

The trailing punctuation problem

There are two distinct failures at the end of a URL and they are often conflated.

The first is linkification. Autolinking regular expressions frequently match trailing punctuation as part of the URL, so the full stop that ended the sentence becomes part of the href. That is a parsing bug, it happens in LTR text too, and it is fixed by trimming trailing ., ,, ), ] and : from the match — with the standard exception that a closing parenthesis is kept if the URL contains a matching opening one.

The second is bidi. A full stop after a URL in an RTL sentence sits between an L run and whatever follows. If what follows is Arabic or the end of the paragraph, N1 or N2 gives it the paragraph direction, and it renders at the left-hand end of the line rather than immediately after the URL. That is correct behaviour for a sentence-final period in right-to-left text, and it looks wrong to the person who wrote it because they were reading the URL as the end of the sentence. If the period genuinely belongs to the URL, it should be inside the isolate; if it ends the sentence, leave it where the algorithm puts it.

Isolate, then wrap

The fix is two independent settings, and applying only one of them is why this bug keeps coming back.

/* isolation fixes ordering; the wrap rules fix overflow */
a.url {
  unicode-bidi: isolate;   /* opaque to the surrounding text */
  direction: ltr;          /* the URL's own base direction   */
  overflow-wrap: anywhere; /* break points inside the string */
}

/* optional, and worth it for very long paths: prefer breaking
   after a separator rather than mid-token */
a.url { word-break: normal; line-break: anywhere; }
<!-- HTML: <bdi> is isolate + dir=auto, so give it an explicit
     direction when you know the content is a URL -->
<p dir="rtl">
  ... <bdi dir="ltr"><a href="https://example.com/docs/a/b?x=1"
  >https://example.com/docs/a/b?x=1</a></bdi>.
</p>

In plain text, with no markup available, the equivalent is to wrap the URL in U+2066 LEFT-TO-RIGHT ISOLATE and U+2069 POP DIRECTIONAL ISOLATE. Use an isolate rather than an embedding or an override: an isolate makes the run opaque in both directions, so the URL cannot pull the following punctuation into itself and the surrounding Arabic cannot reach inside. Do it at render time, not in stored data — an invisible character inside a stored URL will break comparison and deduplication exactly as described for spreadsheet values in exporting RTL text to a spreadsheet.

One caveat on isolates: they were added in Unicode 6.3 and are universal in browsers, and they are not universal outside them. Some terminal emulators, older PDF toolchains and embedded renderers ignore them or, worse, render them as visible boxes. Test in the surface you are actually shipping to.

When the URL itself is bidirectional

Here is the case that isolation does not fix, and it is increasingly common because internationalised domain names and non-ASCII paths are ordinary now. Consider a URL whose path segment is written in Arabic script. Inside the isolate, at base direction left-to-right, that segment is a strong right-to-left run — so it is reordered relative to the rest of the URL, and the solidi around it are neutrals resolving between an L run and an R run. The URL reorders internally, inside a correctly-isolated element, and no outer markup changes that.

There is no display fix, because the display is correct: those really are right-to-left characters and they really do read right-to-left. The options are all about what you show:

  • Show the percent-encoded form. Unambiguous, all-ASCII, single direction, and ugly. Right for anything the reader will copy, verify or paste into a terminal.
  • Show a shortened display form — host plus an ellipsis — with the full URL in the href and the title attribute. Right for prose. It also sidesteps the wrapping problem entirely.
  • Show the decoded form and accept the reordering, which is what a native reader expects anyway, and what a browser address bar does.

What not to do is force the whole URL with a directional override. U+202D will lay out the Arabic path segment character by character in left-to-right order, which is unreadable to anyone who can read it, and it will not round-trip through copy-paste in any useful way.