<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Letras Bonitas</title>
    <description>The latest articles on DEV Community by Letras Bonitas (@letrasbonitasz).</description>
    <link>https://dev.to/letrasbonitasz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4209455%2Fe37b81d9-8412-4d24-8ecd-53a51f343ac3.png</url>
      <title>DEV Community: Letras Bonitas</title>
      <link>https://dev.to/letrasbonitasz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/letrasbonitasz"/>
    <language>en</language>
    <item>
      <title>How Fancy Letters Really Work: A Developer's Tour of Unicode's Hidden Alphabets</title>
      <dc:creator>Letras Bonitas</dc:creator>
      <pubDate>Mon, 26 Oct 2026 20:04:16 +0000</pubDate>
      <link>https://dev.to/letrasbonitasz/how-fancy-letters-really-work-a-developers-tour-of-unicodes-hidden-alphabets-16fa</link>
      <guid>https://dev.to/letrasbonitasz/how-fancy-letters-really-work-a-developers-tour-of-unicodes-hidden-alphabets-16fa</guid>
      <description>&lt;p&gt;You've seen it in Instagram bios, Discord names and game nicknames: 𝐛𝐨𝐥𝐝, 𝘪𝘵𝘢𝘭𝘪𝘤, 𝓈𝒸𝓇𝒾𝓅𝓉, 𝔣𝔯𝔞𝔨𝔱𝔲𝔯, ⓒⓘⓡⓒⓛⓔⓓ, ｆｕｌｌｗｉｄｔｈ and t̷̢͙h̶̤͝i̵͚͑s̸̱̾ kind of chaos, all pasted into fields that only accept plain text.&lt;/p&gt;

&lt;p&gt;None of that is a font. No CSS, no rich text, no &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; tag. Every one of those glyphs is its own Unicode code point, and the "fancy text generators" all over the web are mostly lookup tables. This post goes through the blocks those characters come from, why the alphabets have strange gaps, and what they cost you in accessibility and searchability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fonts vs. characters
&lt;/h2&gt;

&lt;p&gt;Normally "bold" is presentation. The character &lt;code&gt;A&lt;/code&gt; (U+0041) stays the same, and your font or CSS decides how heavy it looks. Copy it somewhere else and the boldness is gone.&lt;/p&gt;

&lt;p&gt;Fancy text works the other way. &lt;code&gt;𝐀&lt;/code&gt; is &lt;strong&gt;U+1D400 MATHEMATICAL BOLD CAPITAL A&lt;/strong&gt;, a separate character from &lt;code&gt;A&lt;/code&gt;. Because the style is part of the character, it survives copy-paste into any plain-text field, provided the reader's device has a font that can draw it.&lt;/p&gt;

&lt;p&gt;That one fact explains both why these characters are useful and most of the trouble they cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Mathematical Alphanumeric Symbols (U+1D400–U+1D7FF)
&lt;/h2&gt;

&lt;p&gt;Most fancy text comes from this block. It was added in &lt;strong&gt;Unicode 3.1 (2001)&lt;/strong&gt;, mainly for mathematicians, because in math notation the style of a letter carries meaning. A bold &lt;strong&gt;x&lt;/strong&gt; might be a vector, a fraktur 𝔤 a Lie algebra, and a double-struck ℝ the real numbers. Those distinctions need to survive in plain text, so Unicode encoded them as separate characters.&lt;/p&gt;

&lt;p&gt;The block contains full Latin alphabets (and some Greek letters and digits) in styles such as:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Style&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Starts at (capital A)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bold&lt;/td&gt;
&lt;td&gt;𝐀𝐁𝐂 𝐚𝐛𝐜&lt;/td&gt;
&lt;td&gt;U+1D400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Italic&lt;/td&gt;
&lt;td&gt;𝐴𝐵𝐶 𝑎𝑏𝑐&lt;/td&gt;
&lt;td&gt;U+1D434&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bold italic&lt;/td&gt;
&lt;td&gt;𝑨𝑩𝑪&lt;/td&gt;
&lt;td&gt;U+1D468&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script&lt;/td&gt;
&lt;td&gt;𝒜𝒞𝒟&lt;/td&gt;
&lt;td&gt;U+1D49C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bold script&lt;/td&gt;
&lt;td&gt;𝓐𝓑𝓒&lt;/td&gt;
&lt;td&gt;U+1D4D0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fraktur&lt;/td&gt;
&lt;td&gt;𝔄𝔅𝔇&lt;/td&gt;
&lt;td&gt;U+1D504&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Double-struck&lt;/td&gt;
&lt;td&gt;𝔸𝔹𝔻&lt;/td&gt;
&lt;td&gt;U+1D538&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bold fraktur&lt;/td&gt;
&lt;td&gt;𝕬𝕭𝕮&lt;/td&gt;
&lt;td&gt;U+1D56C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sans-serif (+ bold/italic)&lt;/td&gt;
&lt;td&gt;𝖠 𝗔 𝘈 𝘼&lt;/td&gt;
&lt;td&gt;U+1D5A0…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monospace&lt;/td&gt;
&lt;td&gt;𝙰𝙱𝙲&lt;/td&gt;
&lt;td&gt;U+1D670&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are also bold, double-struck, sans-serif and monospace &lt;strong&gt;digits&lt;/strong&gt; (𝟎𝟏𝟐, 𝟘𝟙𝟚, 𝟶𝟷𝟸) near the end of the block, starting at U+1D7CE.&lt;/p&gt;

&lt;h3&gt;
  
  
  The holes, and why they exist
&lt;/h3&gt;

&lt;p&gt;Try generating italic "hello" by adding a fixed offset and you'll hit a problem: &lt;strong&gt;U+1D455&lt;/strong&gt;, where italic small &lt;em&gt;h&lt;/em&gt; should be, is unassigned. The same goes for several letters in the script, fraktur and double-struck alphabets.&lt;/p&gt;

&lt;p&gt;The reason is history. Some of these letters were already in Unicode before 2001, in the &lt;strong&gt;Letterlike Symbols&lt;/strong&gt; block (U+2100–U+214F), because they were common symbols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ℎ&lt;/code&gt; U+210E &lt;strong&gt;PLANCK CONSTANT&lt;/strong&gt;, which serves as the italic small h&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ℬ&lt;/code&gt; U+212C SCRIPT CAPITAL B, &lt;code&gt;ℰ&lt;/code&gt;, &lt;code&gt;ℱ&lt;/code&gt;, &lt;code&gt;ℋ&lt;/code&gt;, &lt;code&gt;ℐ&lt;/code&gt;, &lt;code&gt;ℒ&lt;/code&gt;, &lt;code&gt;ℳ&lt;/code&gt;, &lt;code&gt;ℛ&lt;/code&gt;, plus small &lt;code&gt;ℯ&lt;/code&gt;, &lt;code&gt;ℊ&lt;/code&gt;, &lt;code&gt;ℴ&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ℭ&lt;/code&gt; U+212D BLACK-LETTER CAPITAL C, &lt;code&gt;ℌ&lt;/code&gt;, &lt;code&gt;ℑ&lt;/code&gt;, &lt;code&gt;ℜ&lt;/code&gt;, &lt;code&gt;ℨ&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ℂ&lt;/code&gt; U+2102 DOUBLE-STRUCK CAPITAL C, &lt;code&gt;ℍ&lt;/code&gt;, &lt;code&gt;ℕ&lt;/code&gt;, &lt;code&gt;ℙ&lt;/code&gt;, &lt;code&gt;ℚ&lt;/code&gt;, &lt;code&gt;ℝ&lt;/code&gt;, &lt;code&gt;ℤ&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unicode doesn't encode the same character twice, so the matching slots in the math block were left as reserved holes. Any generator that hasn't special-cased them will output missing characters for words like "Chess" in double-struck.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Enclosed Alphanumerics (U+2460–U+24FF) and the Supplement (U+1F100–U+1F1FF)
&lt;/h2&gt;

&lt;p&gt;The "bubble" letters come from &lt;strong&gt;Enclosed Alphanumerics&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;circled: &lt;code&gt;Ⓐ&lt;/code&gt; U+24B6 … &lt;code&gt;ⓐ&lt;/code&gt; U+24D0 …&lt;/li&gt;
&lt;li&gt;parenthesized: &lt;code&gt;⒜⒝⒞&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;circled and parenthesized numbers: &lt;code&gt;①②③&lt;/code&gt;, &lt;code&gt;⑴⑵⑶&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many of these came into Unicode for compatibility with older East Asian character sets, where enclosed numbers and letters were common in lists and labels.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Enclosed Alphanumeric Supplement&lt;/strong&gt; adds heavier variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;negative circled: &lt;code&gt;🅐&lt;/code&gt; U+1F150 …&lt;/li&gt;
&lt;li&gt;squared: &lt;code&gt;🄰🄱🄲&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;negative squared: &lt;code&gt;🅰&lt;/code&gt; U+1F170 …, the source of the 🅰🅱 "blood type" glyphs. With emoji presentation these display as red emoji on many platforms.&lt;/li&gt;
&lt;li&gt;regional indicator symbols (U+1F1E6–U+1F1FF), which aren't decorative letters. In pairs they form flags: 🇲 + 🇽 = 🇲🇽.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Halfwidth and Fullwidth Forms (U+FF00–U+FFEF)
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ｖａｐｏｒｗａｖｅ ａｅｓｔｈｅｔｉｃ&lt;/code&gt; text uses &lt;strong&gt;fullwidth&lt;/strong&gt; Latin letters such as &lt;code&gt;Ａ&lt;/code&gt; U+FF21 and &lt;code&gt;ａ&lt;/code&gt; U+FF41.&lt;/p&gt;

&lt;p&gt;These come from CJK computing. In Chinese, Japanese and Korean text, characters sit on a square grid, and older East Asian encodings included "wide" versions of Latin letters and digits so they would fill one full cell and line up with ideographs. Halfwidth katakana (&lt;code&gt;ｱｲｳ&lt;/code&gt;) are the reverse case: narrow forms from early systems with limited display space. Unicode kept both for round-trip compatibility with those legacy encodings.&lt;/p&gt;

&lt;p&gt;Out of context, the extra width reads as a "vaporwave" look.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Combining characters, Zalgo, underline and strikethrough
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;combining character&lt;/strong&gt; has no width of its own. It attaches to the character before it. The main range is &lt;strong&gt;Combining Diacritical Marks, U+0300–U+036F&lt;/strong&gt;: &lt;code&gt;e&lt;/code&gt; + U+0301 → &lt;code&gt;é&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unicode doesn't limit how many marks you can stack on one base character. Stack dozens above and below and you get &lt;strong&gt;Zalgo text&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;H̵̡̛̖̪̍e̸̢͚̓ ̴̰̔c̷̺̈́o̶̧͝m̵̙̊e̸̫͒s̷̪̈́&lt;/p&gt;

&lt;p&gt;Renderers try to stack the marks, run out of room, and draw them over neighboring lines.&lt;/p&gt;

&lt;p&gt;The same mechanism gives you underline and strikethrough in plain text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;U+0332&lt;/code&gt; COMBINING LOW LINE after each letter: u̲n̲d̲e̲r̲l̲i̲n̲e̲&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U+0336&lt;/code&gt; COMBINING LONG STROKE OVERLAY: s̶t̶r̶i̶k̶e̶&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U+0335&lt;/code&gt; (short stroke) and &lt;code&gt;U+0338&lt;/code&gt; (solidus overlay) give variations such as s̸l̸a̸s̸h̸&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How cleanly these join depends entirely on the font and the text renderer.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Small caps, superscripts and upside-down text
&lt;/h2&gt;

&lt;p&gt;Unicode has &lt;strong&gt;no small-caps alphabet&lt;/strong&gt;. Generators borrow letters from linguistics instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IPA&lt;/strong&gt; (U+0250–U+02AF) has &lt;code&gt;ʀ ɢ ɪ ʜ ʟ ɴ ʏ ʙ&lt;/code&gt;, which phoneticians use as real symbols.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phonetic Extensions&lt;/strong&gt; (U+1D00–U+1D7F) adds &lt;code&gt;ᴀ&lt;/code&gt; U+1D00, &lt;code&gt;ᴄ ᴅ ᴇ ᴊ ᴋ ᴍ ᴏ ᴘ ᴛ ᴜ ᴠ ᴡ ᴢ&lt;/code&gt;, and modifier letters such as &lt;code&gt;ᴬ ᴮ ᴰ&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result, ꜱᴍᴀʟʟ ᴄᴀᴘꜱ, is assembled from several blocks, which is why some letters look slightly off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Superscript&lt;/strong&gt; text (ˢᵘᵖᵉʳˢᶜʳⁱᵖᵗ) works the same way, combining modifier letters from Spacing Modifier Letters, Phonetic Extensions and Superscripts and Subscripts. A few letters have no superscript form at all; there is no dedicated superscript small q, for example. Generators either substitute something similar or leave the letter as it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upside-down text&lt;/strong&gt; (ʇxǝʇ uʍop-ǝpᴉsdn) combines character reversal with a lookup table of look-alikes: &lt;code&gt;ɐ&lt;/code&gt; U+0250 LATIN SMALL LETTER TURNED A, &lt;code&gt;ǝ&lt;/code&gt;, &lt;code&gt;ɥ&lt;/code&gt;, &lt;code&gt;ɯ&lt;/code&gt;, &lt;code&gt;ʇ&lt;/code&gt;, plus punctuation such as &lt;code&gt;¿&lt;/code&gt; and &lt;code&gt;¡&lt;/code&gt;. These are mostly real IPA letters used for their shape, not true rotated copies.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A tiny generator in JavaScript
&lt;/h2&gt;

&lt;p&gt;Since the bold block has no holes, a bold generator is just arithmetic on code points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toMathBold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;codePointAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x41&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x5a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCodePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1d400&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0x41&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// A–Z&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x61&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x7a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCodePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1d41a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0x61&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// a–z&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x30&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x39&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCodePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1d7ce&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0x30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 0–9&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toMathBold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World 2026&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                     &lt;span class="c1"&gt;// 𝐇𝐞𝐥𝐥𝐨 𝐖𝐨𝐫𝐥𝐝 𝟐𝟎𝟐𝟔&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 30 16&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NFKC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// Hello World 2026&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to notice in the output (I ran this on Node 22):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;out.length&lt;/code&gt; is 30, not 16.&lt;/strong&gt; These characters are outside the Basic Multilingual Plane, so each one takes a UTF-16 &lt;em&gt;surrogate pair&lt;/em&gt;. Use &lt;code&gt;codePointAt&lt;/code&gt;, &lt;code&gt;String.fromCodePoint&lt;/code&gt; and &lt;code&gt;[...str]&lt;/code&gt;, not &lt;code&gt;charCodeAt&lt;/code&gt; or &lt;code&gt;split("")&lt;/code&gt;, or you'll split characters in half. It also matters for character limits: a platform counting UTF-16 units sees a 16-character name as 30.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NFKC normalization turns it back into "Hello World 2026".&lt;/strong&gt; These characters have &lt;em&gt;compatibility decompositions&lt;/em&gt; to plain letters. That's useful for search and moderation pipelines, and it shows that Unicode itself treats them as styled versions of ordinary letters.&lt;/li&gt;
&lt;li&gt;For italic, script, fraktur or double-struck, you need an &lt;strong&gt;exception map&lt;/strong&gt; for the Letterlike Symbols holes (&lt;code&gt;h → ℎ&lt;/code&gt;, &lt;code&gt;C → ℂ&lt;/code&gt; and so on). Otherwise you'll output unassigned code points.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. Caveats: when &lt;em&gt;not&lt;/em&gt; to use fancy text
&lt;/h2&gt;

&lt;p&gt;These characters are fun, but they have real costs, and you should know about them before putting them in front of users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility.&lt;/strong&gt; Screen readers handle math alphanumerics inconsistently. Depending on the reader and its settings, &lt;code&gt;𝐇𝐞𝐥𝐥𝐨&lt;/code&gt; may be read as "mathematical bold capital H, mathematical bold small e…", spelled out letter by letter, or skipped entirely. Zalgo and upside-down text are worse. If someone who uses a screen reader needs to understand it, don't style it this way. At most, style a word or two and keep the important information in plain text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search and indexing.&lt;/strong&gt; To a naive search, &lt;code&gt;𝐜𝐨𝐟𝐟𝐞𝐞&lt;/code&gt; and &lt;code&gt;coffee&lt;/code&gt; are different strings. Some systems apply NFKC or similar folding and some don't, so a fancy-text username or bio may not show up when people search for the plain word. Don't put your brand name, handle or keywords only in fancy letters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform support.&lt;/strong&gt; Most fields on Instagram, TikTok, WhatsApp, Discord and X accept these characters because they're just Unicode. Rendering depends on the viewer's fonts, and older Android phones in particular may show &lt;code&gt;□&lt;/code&gt; boxes. Games are stricter. Free Fire nicknames, for example, are a popular use, but games validate names against their own character rules and length limits, which can change, so test on the platform before you commit. Display names and handles also usually follow different rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copy-paste and data.&lt;/strong&gt; The style travels with the text, so it ends up in places you didn't intend: spreadsheets, CSV exports, CRM fields, &lt;code&gt;grep&lt;/code&gt; failures. For developers, that also means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validate and normalize (NFKC) usernames to prevent look-alike impersonation (𝐚𝐝𝐦𝐢𝐧 vs admin)&lt;/li&gt;
&lt;li&gt;count graphemes or code points, not UTF-16 units, when enforcing limits&lt;/li&gt;
&lt;li&gt;strip or limit combining marks if Zalgo would break your layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Never&lt;/strong&gt; use them for passwords, email addresses, URLs, legal or medical text, or anything someone needs to type back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;To see all of these blocks side by side without writing your own lookup tables, try &lt;strong&gt;&lt;a href="https://letrasbonitasz.com" rel="noopener noreferrer"&gt;Letras Bonitasz&lt;/a&gt;&lt;/strong&gt;. It's a free Spanish-language generator: type a word and it shows the math, enclosed, fullwidth, small-caps and upside-down styles, and you can copy whichever you want. It has a dedicated &lt;a href="https://letrasbonitasz.com/texto-zalgo/" rel="noopener noreferrer"&gt;Zalgo text page&lt;/a&gt; for testing how your app handles stacked combining marks, which works well as test input for UI layouts.&lt;/p&gt;

&lt;p&gt;A fun exercise: paste its output into your own app's username field, run it through &lt;code&gt;normalize("NFKC")&lt;/code&gt;, and see what your validation, search and length checks do with it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Further reading: Wikipedia's articles on Mathematical Alphanumeric Symbols, Enclosed Alphanumerics, Halfwidth and Fullwidth Forms, Combining character and Zalgo text, and the official charts at unicode.org/charts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>unicode</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>typography</category>
    </item>
  </channel>
</rss>
