<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Arabic Keyboard Dev Notes]]></title><description><![CDATA[The Arabic Keyboard Dev Notes]]></description><link>https://thearabickeyboard.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 20:06:28 GMT</lastBuildDate><atom:link href="https://thearabickeyboard.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Arabic "fancy text" doesn't exist: what actually survives copy and paste]]></title><description><![CDATA[Why Arabic fancy text generators fail, and what survives copy and paste: ligatures like U+FDFD, tatweel, joiners, harakat and bidi marks.]]></description><link>https://thearabickeyboard.hashnode.dev/arabic-fancy-text-doesn-t-exist-what-actually-survives-copy-and-paste</link><guid isPermaLink="true">https://thearabickeyboard.hashnode.dev/arabic-fancy-text-doesn-t-exist-what-actually-survives-copy-and-paste</guid><category><![CDATA[unicode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[i18n]]></category><category><![CDATA[typography]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[The Arabic Keyboard]]></dc:creator><pubDate>Fri, 30 Oct 2026 10:23:56 GMT</pubDate><content:encoded><![CDATA[<p>Every week someone asks for an "Arabic font copy and paste" tool, the kind that turns <strong>hello</strong> into 𝓱𝓮𝓵𝓵𝓸 for an Instagram bio. For Latin that works, because Unicode has a block of styled letters (Mathematical Alphanumeric Symbols) that apps render without needing any font support.</p>
<p>For Arabic it mostly doesn't work. The reasons are a useful tour of how Arabic is encoded, so here are the pieces, what each one does when it's pasted somewhere, and which are safe to use.</p>
<h2>1. An Arabic letter is one code point, its shape is the font's job</h2>
<p>Arabic is cursive. Most letters have up to four shapes: isolated, initial, medial and final. ب, for example, is drawn ﺏ alone, ﺑ at the start, ﺒ in the middle and ﺐ at the end.</p>
<p>Unicode stores <strong>one</strong> code point, <code>U+0628 ARABIC LETTER BEH</code>, and the text-shaping engine (HarfBuzz, CoreText, DirectWrite) picks the shape from the neighbouring letters. The style comes from the font: Kufic, Naskh, Nastaliq. That is why "copy the calligraphy" can't work. The style lives in the font, and a font doesn't travel with plain text.</p>
<h2>2. The "styled Arabic" block exists, and it's a trap</h2>
<p>Unicode does have <strong>Arabic Mathematical Alphabetic Symbols</strong> (<code>U+1EE00–U+1EEFF</code>), with initial, tailed, stretched, looped and double-struck letters. They look like exactly what a fancy-text generator needs. They're meant for mathematical notation, so:</p>
<ul>
<li><strong>They don't join.</strong> Each one is a standalone symbol, so a word comes out as a row of separate glyphs instead of connected script.</li>
<li><strong>Few fonts cover them.</strong> On many phones they show as empty boxes.</li>
<li><strong>They aren't the letters.</strong> Search, find-in-page and screen readers don't treat them as Arabic words.</li>
</ul>
<p>If you build a text tool, don't map Arabic input onto this block.</p>
<h2>3. Presentation forms: legacy shapes and a few real gems</h2>
<p><strong>Arabic Presentation Forms-A and -B</strong> (<code>U+FB50–U+FDFF</code>, <code>U+FE70–U+FEFF</code>) encode the <em>contextual shapes</em> as separate characters, a leftover from systems that couldn't do shaping. You'll find them in old PDFs: copy text out of one and you often get <code>U+FE91</code> ﺑ instead of <code>U+0628</code>.</p>
<p>Mostly they cause bugs. A string full of presentation forms only matches its normal spelling after NFKC normalization, and many search boxes, databases and spell-checkers don't normalize. If you handle user input, normalize it:</p>
<pre><code class="language-js">const clean = input.normalize("NFKC");   // ﺑﺴﻢ (presentation forms) → بسم (letters)
</code></pre>
<p>The exception, and the one thing people really can copy and paste, is the <strong>whole-word ligatures</strong> at the end of Presentation Forms-A:</p>
<table>
<thead>
<tr>
<th>Char</th>
<th>Code point</th>
<th>Reads</th>
</tr>
</thead>
<tbody><tr>
<td>﷽</td>
<td><code>U+FDFD</code></td>
<td>بسم الله الرحمن الرحيم (Bismillah)</td>
</tr>
<tr>
<td>ﷲ</td>
<td><code>U+FDF2</code></td>
<td>الله</td>
</tr>
<tr>
<td>ﷴ</td>
<td><code>U+FDF4</code></td>
<td>محمد</td>
</tr>
<tr>
<td>ﷺ</td>
<td><code>U+FDFA</code></td>
<td>صلى الله عليه وسلم</td>
</tr>
<tr>
<td>ﷻ</td>
<td><code>U+FDFB</code></td>
<td>جل جلاله</td>
</tr>
</tbody></table>
<p>Each is one character that draws a whole phrase in calligraphic form, and it pastes into almost any app. The caveats are real: the size and look depend on the app's font, and a few older devices show a box. Normalization is inconsistent too. NFKC expands ﷲ, ﷴ, ﷺ and ﷻ back into their letters, which is usually what you want for search, but ﷽ has <strong>no</strong> decomposition at all. It stays a single symbol that will never match the words بسم الله, so don't use it where the phrase needs to be findable:</p>
<pre><code class="language-js">"ﷺ".normalize("NFKC");   // "صلى الله عليه وسلم"
"﷽".normalize("NFKC");   // "﷽"  (unchanged)
</code></pre>
<p>Unicode 14 added more (<code>U+FDCF</code>, <code>U+FDFE</code>, <code>U+FDFF</code>). Font support for those is still thin, so test before you rely on them.</p>
<h2>4. Tatweel: the only "style" that survives a paste</h2>
<p><code>U+0640 ARABIC TATWEEL</code> (ـ), also called kashida, is a stretching stroke placed between two joined letters. Calligraphers lengthen joins for rhythm and justification, and tatweel gives plain text a similar look:</p>
<pre><code class="language-plaintext">بسم الله        →  بســـم الله
الحمد لله       →  الحمـــد لله
</code></pre>
<p>It is an ordinary character, so it survives any paste. Two rules:</p>
<ol>
<li><strong>Only between letters that join.</strong> ا د ذ ر ز و never connect to the next letter, so a tatweel placed after them floats on its own.</li>
<li><strong>It breaks matching.</strong> <code>بســـم</code> is not <code>بسم</code> to a search index. For a username or a bio line it doesn't matter; for content people need to find, keep it out.</li>
</ol>
<p>If you strip harakat in a tool, decide whether tatweel goes too. We strip it with the marks, because it isn't part of the spelling.</p>
<h2>5. Joiners: showing a letter's shape out of context</h2>
<p>To display a letter's medial form on its own, for example in a lesson that says "this is ب in the middle of a word", put a joiner on both sides:</p>
<pre><code class="language-js">const ZWJ = "\u200D";
const medialBeh = ZWJ + "ب" + ZWJ;   // displays the medial form ﺒ
</code></pre>
<p><code>U+200D ZERO WIDTH JOINER</code> asks the shaper to join, and <code>U+200C ZERO WIDTH NON-JOINER</code> asks it to break a join. Use ZWNJ in Persian, where it is part of the spelling (<code>می‌خواهم</code>). In Arabic, ZWNJ is almost always an accident, so treat it as a bug in user input.</p>
<h2>6. Harakat are combining marks, so mind the order</h2>
<p>Short vowels and other marks (<code>U+064B–U+0652</code>, plus <code>U+0670</code> dagger alif) are combining characters that stack on the previous letter. Two things to know:</p>
<ul>
<li><strong>NFC reorders them.</strong> Shadda has combining class 33 and fatha has 30, so normalization puts <em>fatha before shadda</em> even if the user typed shadda first. Good fonts render both orders the same. If you compare strings with marks, normalize both sides first.</li>
<li><strong>Stripping them is a one-liner</strong>, which is useful for search and for logos:</li>
</ul>
<pre><code class="language-js">const noHarakat = s.replace(/[\u064B-\u0652\u0670]/g, "");
</code></pre>
<h2>7. Bidi: why your pasted bio looks scrambled</h2>
<p>Paste <code>@user مرحبا 2026!</code> into a left-to-right field and the punctuation and numbers often land on the wrong side. Arabic is right-to-left; digits and neutral characters take their direction from what surrounds them.</p>
<p>The fixes, from least to most robust:</p>
<ul>
<li><code>U+200F RIGHT-TO-LEFT MARK</code> (RLM): an invisible strong RTL character. Put it after trailing punctuation so the <code>!</code> stays at the Arabic end.</li>
<li><code>U+2067 RIGHT-TO-LEFT ISOLATE</code> … <code>U+2069 POP DIRECTIONAL ISOLATE</code>: wraps a run so it can't disturb the text around it. Use it when you insert user names into a sentence.</li>
<li>In HTML, use <code>&lt;bdi&gt;</code> and <code>dir="auto"</code> rather than inserting marks yourself.</li>
</ul>
<h2>So what should a "copy and paste" tool offer?</h2>
<p>Our conclusion after building one:</p>
<ol>
<li><strong>Copy gives real Unicode letters</strong>, and you tell people plainly that the style won't come along.</li>
<li><strong>An image or vector export</strong> (PNG, SVG with the font embedded) is how the calligraphic look travels.</li>
<li><strong>A short list of the whole-word ligatures</strong> (﷽ ﷲ ﷺ), clearly labelled as symbols with their caveats.</li>
<li><strong>Tatweel</strong> for people who just want a stylised bio line, with the joining rule spelled out.</li>
</ol>
<p>That's what we built into our <a href="https://www.thearabickeyboard.com/arabic-calligraphy-generator/">Arabic calligraphy generator</a>. It has 22 open-licence fonts, it runs entirely in the browser, and it doesn't use any styled-letter trickery.</p>
<p>If the problem starts one step earlier, because you need to type Arabic on a computer with no Arabic layout installed, our <a href="https://www.thearabickeyboard.com/">online Arabic keyboard</a> works in any browser. French speakers can use the same tool as a <a href="https://www.thearabickeyboard.com/clavier-arabe/">clavier arabe en ligne</a>.</p>
<p>If you've hit an Arabic Unicode edge case that isn't covered here, tell me about it in the comments.</p>
]]></content:encoded></item></channel></rss>