Furigana in Markdown: Four Syntaxes, and Which One Survives
To write furigana in Markdown so it survives leaving the app, use HTML <ruby> with <rp> fallbacks: <ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby>. It is the only one of the four common syntaxes that renders without a plugin, and stripped of its tags it still reads 漢字(かんじ). Keep the base word unbroken in the file, so search still finds it.
The question is live. "Furifont, a Japanese font that shows furigana," posted to Hacker News on 15 October 2026, drew 409 points and 83 comments. One reply asked the obvious thing: "Couldn't you just use Ruby tags for a website?"1
Note-takers ask it too — and they have more syntaxes to choose from. Obsidian's community registry lists eight plugins built for ruby or furigana, with 39,773 combined downloads as of 23 October 20262 — and the plugins do not share a syntax.
Four source forms circulate — raw HTML, Aozora Bunko's double angle brackets, a brace syntax from DenDenMarkdown, and three invisible Unicode characters. Each one was run on 23 October 2026 through a plain CommonMark renderer, GitHub's Markdown API, a tag remover and grep. The results are below, followed by one rule.
The same method covers Chinese pinyin and bopomofo, and Korean readings over hanja.
What furigana is, in a plain-text file
Furigana is a reading written above or beside a word, usually small kana over kanji. In a plain-text file it becomes a second layer of text: the base word, plus an annotation tied to it. Every syntax below is one way of encoding that pairing — and each one loses something different when the file moves.
The web standard names it plainly. The WHATWG HTML specification, describing the ruby element, says: "In Japanese, this form of typography is also known as furigana."3 MDN's reference gives the general definition: "The <ruby> HTML element represents small annotations that are rendered above, below, or next to base text, usually used for showing the pronunciation of East Asian characters."4
Scholarly text encoders reached the same place by a different road. Kazuhiro Okada, Satoru Nakamura and Kiyonori Nagasaki describe ruby elements that entered the TEI Guidelines in release 4.2.0, a release codenamed "Ruby."5 Their glossary adds one line worth keeping: "In a plain text transcription, parenthesized text shows ruby text."5
Hold on to that sentence — it describes the fallback this whole reference is aiming for.
The four syntaxes at a glance
Four source forms are in use. HTML <ruby> renders wherever raw HTML is allowed. Aozora Bunko's 漢字《かんじ》 reads cleanly as text but needs a converter. Brace syntax {漢字|かんじ} needs a plugin. Unicode's annotation characters U+FFF9–U+FFFB are invisible, and Unicode itself discourages them. Only the first renders without help.
| File form | Plain CommonMark | GitHub Markdown API | Tags stripped | grep 漢字 |
|---|---|---|---|---|
<ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby> | passed through as HTML | renders — ruby, rt, rp kept | 漢字(かんじ) | found |
<ruby>漢<rt>かん</rt>字<rt>じ</rt></ruby> | passed through | renders | 漢かん字じ | missed |
<ruby><rb>漢</rb><rb>字</rb><rt>かん</rt><rt>じ</rt></ruby> | passed through | <rb> dropped | 漢字かんじ | missed |
漢字《かんじ》 | literal text | literal text | 漢字《かんじ》 | found |
漢《かん》字《じ》 | literal text | literal text | 漢《かん》字《じ》 | missed |
{漢字|かんじ} | literal text | literal text; splits a table cell | {漢字|かんじ} | found |
{漢字|かん|じ} | literal text | literal text | {漢字|かん|じ} | found |
{漢|かん}{字|じ} | literal text | literal text | {漢|かん}{字|じ} | missed |
U+FFF9 漢字 U+FFFA かんじ U+FFFB | passed through, invisible | passed through, invisible | 漢字かんじ if the controls are filtered | found |
Method, run on 23 October 2026: "Plain CommonMark" is a reference-preset renderer with no plugins. "GitHub Markdown API" is POST /markdown in gfm mode6 — the renderer endpoint, not a live README page. "Tags stripped" is the text left when every HTML tag is removed. grep is GNU grep 3.12 over nine one-line files.
One column decides most cases — the fourth. It shows what a reader gets when the markup is lost.
Syntax 1: HTML <ruby> with <rp>
HTML ruby is the only syntax a Markdown renderer can hand straight to a browser, because Markdown allows inline HTML. Wrap the base in <ruby>, put the reading in <rt>, and add <rp> parentheses. Browsers that render ruby hide the parentheses. Anything that strips the tags leaves 漢字(かんじ) — still readable.
<ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby>
The <rp> element is easy to leave out, and it is the part that makes the file portable. The WHATWG spec defines its job: "The rp element can be used to provide parentheses or other content around a ruby text component of a ruby annotation, to be shown by user agents that don't support ruby annotations."3 Old browsers were the original audience. Today the bigger audience is every pipeline that throws tags away — copy-paste, text export, search indexes.
Browser support is settled — and has been for over a decade. MDN marks <ruby> as Baseline "Widely available": "It’s been available across browsers since July 2015."4 Richard Ishida, writing for W3C Internationalization, is blunter: "Simple ruby works everywhere. All major browsers correctly render simple, single-sided ruby (one annotation per base)."7
That claim is about browsers. A note app's preview pane is a different surface — it may sanitize raw HTML, or strip it.
Markdown accepts HTML at all because of a design principle covered in Markdown vs HTML vs Typst: An Honest Comparison of Three Plain-Text Formats. How inline HTML fares when another editor rewrites your file is covered in Google Docs Now Edits Your .md Files — Check What It Rewrites Before You Open Your Notes There.
HTML ruby comes in three shapes, and they behave differently once the file leaves the app:
<!-- group ruby: one reading for the whole word -->
<ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby>
<!-- mono ruby, interleaved: one reading per character -->
<ruby>漢<rt>かん</rt>字<rt>じ</rt></ruby>
<!-- mono ruby, tabular: all bases first, then all readings -->
<ruby><rb>漢</rb><rb>字</rb><rt>かん</rt><rt>じ</rt></ruby>
GitHub's Markdown API kept three of the four ruby tags — ruby, rt, rp — and dropped <rb>.6 The tabular form therefore arrives as this:
<p><ruby>漢字<rt>かん</rt><rt>じ</rt></ruby></p>
Two readings now hang off one base — not what the author wrote. The group form came through intact.
The cost of HTML ruby is noise — a sentence with three annotated words is hard to read in the raw file.
Syntax 2: Aozora Bunko's double angle brackets
The Japanese digital library Aozora Bunko (青空文庫) writes ruby as the base followed by the reading in double angle brackets: 青空文庫《あおぞらぶんこ》. The source reads almost like a printed page, and the base word stays whole for search. Nothing renders it as ruby without a converter or a plugin — it shows as literal text.
Aozora's annotation guide states the rule in one line: "ルビは、「《 》」を用いて、次のように書きます。"8 (Ruby is written with 《 》, as follows.) Its own example:
青空文庫《あおぞらぶんこ》
When the base mixes character types, the guide asks for a full-width vertical bar at the start of the base: "先頭に「|」を入れて範囲を特定してください"8 (put | at the start to mark the range). Its example mixes katakana and kanji:
霧の|ロンドン警視庁《スコットランドヤード》
In a separate paragraph, the same guide says that when the base is a single character type, "「|」はいりません"8 — the bar is not needed.
Aozora's converter turns the notation into HTML ruby, with full-width parentheses as the <rp> fallback8:
<ruby><rb>青空文庫</rb><rp>(</rp><rt>あおぞらぶんこ</rt><rp>)</rp></ruby>
That output uses <rb>, which GitHub's API drops. With a single base, nothing breaks — the base text stays inside <ruby>, and the line still reads correctly.
The bar matters for portability, too. The full-width | is not Markdown's table delimiter. On GitHub's Markdown API, both Aozora examples above sat inside a table row without splitting the cell.6
For a note that stays plain text, this is the most readable source of the four.
Syntax 3: brace syntax, {漢字|かんじ}
Brace syntax puts the base and the reading inside curly braces, separated by a half-width pipe: {漢字|かんじ}. It comes from DenDenMarkdown, a Japanese e-book Markdown dialect documented by 2013. It is compact and keeps the base searchable, but renders nowhere without a plugin — and its pipe breaks Markdown tables.
Credit belongs to the originator — not to the plugins that spread it. DenDenMarkdown (でんでんマークダウン), from 電書ちゃんねる, already showed both brace forms in the earliest Internet Archive capture of its syntax page, dated 18 February 2013.9
The markdown-it-ruby package, created in 2017, says so in its README: "Markup is based on DenDenMarkdown definition."10 Obsidian's most-downloaded furigana plugin, Markdown Furigana, follows that package: "Based off of markdown-it-ruby syntax. All rendering is done post-processing when previewing, so your notes are not modified."11
DenDen's group form puts one reading on the whole word:
{電子出版|でんししゅっぱん}を手軽に
Its per-character form adds one reading per base character, separated by more pipes:
{電子出版|でん|し|しゅっ|ぱん}を手軽に
DenDen renders that per-character line as mono ruby12:
<ruby>電<rt>でん</rt>子<rt>し</rt>出<rt>しゅっ</rt>版<rt>ぱん</rt></ruby>
The count has to match. DenDen's rule: "親文字の文字数とルビ文字のまとまりの数が一致している必要があります。一致しない場合にはグループルビになります。"12 (The number of base characters must equal the number of reading groups; if they do not match, the result is group ruby.)
This per-character form has a property no other syntax here has. The reading is split per character, but the base 電子出版 stays one unbroken run in the file — so search still finds it.
The same braces carry other scripts. The Markdown Furigana README shows pinyin, bopomofo and Korean hangul over hanja11:
{北京|Běi|jīng}
{北京|ㄅㄟˇ|ㄐㄧㄥ}
{韓國|한|국}
Tables are the trap. The Japanese Novel Ruby plugin's README warns: "Using the half-width pipe | as a ruby start delimiter inside tables will break the display."13 GitHub's Markdown API shows the mechanism. In a two-column table, this row:
| Syntax | Note |
|---|---|
| {漢字|かんじ} | brace in a table |
came back as two cells split at the pipe, and the third cell was lost6:
<td>{漢字</td>
<td>かんじ}</td>
The plugins are not interchangeable, either. Japanese Novel Ruby's README says plainly: "This plugin doesn't support markdown ruby format."13 Another library, furigana-markdown-it, uses yet another shape — [猫]{ねこ} — and renders it with corner brackets as the fallback14:
<ruby>猫<rp>【</rp><rt>ねこ</rt><rp>】</rp></ruby>
A note written for one plugin is literal text to the next — braces, pipes and all.
Syntax 4: Unicode's interlinear annotation characters
Unicode reserves three invisible characters for annotations: U+FFF9 marks the start of the annotated text, U+FFFA separates it from the annotation, and U+FFFB ends it. Markdown renderers pass them through untouched because nothing interprets them. The Unicode Standard itself tells you not to use them in files you exchange.
Here is the form, shown as code points — the characters themselves cannot be seen:
U+FFF9 漢字 U+FFFA かんじ U+FFFB
anchor base separator reading terminator
The Unicode Standard 18.0, section 23.8.3, is direct: "Usage of the annotation characters in plain text interchange is strongly discouraged without prior agreement between the sender and the receiver, because the content may be misinterpreted otherwise. Simply filtering out the annotation characters on input will produce an unreadable result or, even worse, an opposite meaning."15
The failure is quiet. Filter the three controls and the reading runs straight into the base — 漢字かんじ — with no mark of where one ends. Characters you cannot see are a different layer of the plain-text problem, covered in Why Your Notes Show Garbled Characters: What 'Plain Text' Actually Means at the Byte Level.
Invisible markup is the worst kind for a note — you cannot see it to fix it.
Which syntax keeps the word searchable
Search finds a word only where the file keeps it contiguous. Across nine one-line test files, grep 漢字 found five and missed four. Every miss put a reading, or a tag, between the two kanji. Group ruby, Aozora's group form, both DenDen brace forms and the Unicode form all kept 漢字 whole.
$ grep -l 漢字 *.md
1-html-group-rp.md
4-aozora-group.md
6-brace-group.md
7-brace-denden-per-char.md
9-unicode-fff9.md
$ grep -L 漢字 *.md
2-html-interleaved.md
3-html-tabular.md
5-aozora-per-char.md
8-brace-split.md
Richard Ishida makes the same point about the rendered page: "If you are looking for the word 日本語 you won't find it in ruby that uses the interleaved model (since the text being searched actually reads 日に本ほん語ご)."7 W3C's answer for the page is the tabular model, which keeps the page text contiguous. In the file, though, <rb>漢</rb><rb>字</rb> still splits the word — file 3 above was missed.
Here the honest caveat belongs. W3C does not tell you to annotate whole words. Ishida, on using one reading for 日本語: "It may appear that you could produce a similar effect by using group ruby, ie. by having a single annotation that reads にほんご mapped to the whole word 日本語. This would however be disadvantageous in at least a couple ways."7
He reserves group ruby for narrower cases: "Situations where group ruby is appropriate include sequences of base characters that are associated with a single phonetic sound, or semantic ruby that applies to a whole word, or even a phrase."7
Line breaking is one cost — the W3C Working Group Note on Japanese text layout says: "Group-ruby and its base characters are unbreakable, because of their behavior as one object (it is possible to break a line in the middle of the base characters where jukugo-ruby is in use)."16
So this is a trade-off — typesetting against retrieval — not a law. In HTML, keeping the base whole in the file means group ruby. In DenDen's brace syntax it does not — {漢字|かん|じ} gives per-character readings and a findable word.
A font is not a note: where Furifont fits
Furifont, a font by Anthony Fu, draws furigana over plain kanji with no markup at all. It is a display choice: the reading lives in the font, not in the file. Change the font and the reading disappears. Its author warns that the readings can be wrong, because a font cannot see the sentence.
The README states the appeal fairly: "The text stays plain: no <ruby> markup, no JavaScript, no plugin. It works everywhere that supports custom fonts."17 A separate warning box states the limit: "Furigana might be incorrect, due to the limits of fonts: a font sees one run of kanji at a time, not the sentence around it."17
The Hacker News thread added a fair counterpoint. User yorwba: "But you could set this as the default system font for Japanese and enjoy furigana everywhere, even in places that don't support ruby tags at all."1 That is a real use — reading text you do not control.
User teshigahara gave the other side: "Automatic furigana is not really possible to be reliable considering readings heavily rely on context that can't be easily inferred, but I'm sure it will help some people who can't read very well."1
The research agrees with the second comment. Fumikazu Sato, Naoki Yoshinaga and Masaru Kitsuregawa, at LREC 2022, analyzed pronunciation distributions for 203 common Japanese heteronyms, noting that "the ambiguities in pronunciations of heteronyms cause wrong reading, which has a serious impact on the text understanding."18 Their trained BERT classifier reached 0.939 macro-averaged accuracy on 93 heteronyms, against 0.884 for a majority-class baseline.18
Even a model that reads the whole sentence got about 6 percent wrong on average — and a font reads one run of kanji.
A reading you write is a reading you chose — a reading the font draws is a guess.
The rule: which syntax to use
Use HTML <ruby> with <rp> and one reading per word for anything that will be published or opened in other tools. Use Aozora Bunko's 《》 for notes that stay plain text. Use DenDen's per-character brace form only inside a plugin that reads it. Never use U+FFF9–U+FFFB, and never trust a font with readings you need to keep.
- Published or shared notes: HTML group ruby with
<rp>. It renders in browsers and degrades to漢字(かんじ). - Plain-text reading notes: Aozora
漢字《かんじ》, with a full-width|before a mixed-script base. It reads as text, and it survives tables. - A vault tied to one plugin: DenDen's
{電子出版|でん|し|しゅっ|ぱん}. Per-character readings, unbroken base. Keep it out of tables. - Never: the invisible annotation characters, or readings that exist only in a font.
A copy-pasteable block for a note that must travel — every reading here comes from the cited sources:
<!-- Portable furigana: one reading per word, parentheses as the fallback -->
<ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby>
<ruby>青空文庫<rp>(</rp><rt>あおぞらぶんこ</rt><rp>)</rp></ruby>
<ruby>電子出版<rp>(</rp><rt>でんししゅっぱん</rt><rp>)</rp></ruby>
<!-- With every tag stripped, the same lines read: -->
<!-- 漢字(かんじ) -->
<!-- 青空文庫(あおぞらぶんこ) -->
<!-- 電子出版(でんししゅっぱん) -->
And five checks to run before committing a vault to any syntax. Each one catches a failure shown above:
1. Strip the tags. Does the line still read? fails: ruby without <rp>
2. grep the base word. Is it found? fails: per-character HTML, split braces
3. Put it in a table. Does the row survive? fails: half-width | inside braces
4. Open it in a second app. Does it render or read? fails: plugin-only syntaxes
5. Change the font. Is the reading still there? fails: font-drawn furigana
Five checks, one file — if a syntax passes all five, it will outlast the app you wrote it in.
Frequently Asked Questions
How can I add furigana into website content?
Use the HTML ruby element: wrap the word in <ruby>, put the reading in <rt>, and add <rp>(</rp> and <rp>)</rp> around the reading. Browsers have rendered simple ruby since 2015, according to MDN. Where ruby is unsupported or the tags are removed, the rp parentheses leave a readable 漢字(かんじ).
Couldn't you just use Ruby tags for a website?
Yes, when you control the content — ruby tags store the reading you chose. A furigana font such as Furifont works where markup cannot, including text you do not control, but its own README warns the readings can be wrong because a font sees one run of kanji at a time. For notes you write, use tags.
Is there a Markdown syntax for ruby text (furigana)?
No Markdown standard defines ruby. CommonMark and GitHub Flavored Markdown have no ruby syntax; raw HTML <ruby> works wherever the tool passes inline HTML. Brace syntax {漢字|かんじ}, from DenDenMarkdown, and Aozora Bunko's 漢字《かんじ》 are conventions that need a plugin or converter to render as ruby.
Does GitHub Markdown support ruby?
GitHub's Markdown rendering API, tested on 23 October 2026 in gfm mode, kept the ruby, rt and rp tags and dropped rb. Group ruby such as <ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby> came through intact. Brace and Aozora syntaxes came through as literal text. Brace syntax inside a table split the cell.
What happens to furigana when the text is copied or exported?
Anything that strips tags runs the reading into the base. Interleaved ruby becomes 漢かん字じ, and tabular ruby becomes 漢字かんじ. Group ruby with <rp> parentheses becomes 漢字(かんじ), which still reads correctly. That fallback is the reason to include rp every time, even though modern browsers render ruby without it.
Does the same markup work for pinyin, bopomofo, or Korean hanja?
Yes. Ruby is not Japanese-specific: MDN describes it as showing the pronunciation of East Asian characters. The Markdown Furigana README shows brace examples for pinyin ({北京|Běi|jīng}), bopomofo ({北京|ㄅㄟˇ|ㄐㄧㄥ}) and hangul over hanja ({韓國|한|국}). The HTML ruby element accepts any reading text.
Which furigana syntax is best for search?
Any form that keeps the base word unbroken in the file. In a grep test, group HTML ruby, Aozora's 漢字《かんじ》 and DenDen's {漢字|かん|じ} were all found. Interleaved HTML, tabular HTML and split per-character forms were missed, because a tag or a reading sat between the two kanji.
A reading belongs to the text. Write it into the file, in a form that still reads when everything around it is gone.
The brace syntax is DenDenMarkdown's, documented since 2013, and the question that prompted this reference came from the discussion of Anthony Fu's Furifont.
MNMNOTE keeps notes as open Markdown on your own device, so whichever syntax you choose is the one that leaves with the file. mnmnote.com
References
Footnotes
-
Hacker News, "Furifont, a Japanese font that shows furigana," item 50100994, 2026-10-15 (409 points, 83 comments); comments by jbm (50132980), yorwba (50133125), teshigahara (50133846), accessed 2026-10-23. https://news.ycombinator.com/item?id=50100994 ↩ ↩2 ↩3
-
Obsidian,
community-plugin-stats.json, obsidianmd/obsidian-releases, accessed 2026-10-23 (eight ruby/furigana plugins: Markdown Furigana 18,208 · Furigana 7,567 · Japanese Novel Ruby 7,112 · Advanced Ruby 3,231 · Japanese Novel Tool 1,588 · Japanese Furigana 1,122 · Inline Ruby Annotation 934 · Komaki Furigana 11). https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/community-plugin-stats.json ↩ -
WHATWG, HTML Living Standard, §4.5 Text-level semantics (the
rubyandrpelements), accessed 2026-10-23. https://html.spec.whatwg.org/multipage/text-level-semantics.html ↩ ↩2 -
MDN Web Docs, "
<ruby>HTML ruby annotation element," last modified 2026-04-24, accessed 2026-10-23. https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ruby ↩ ↩2 -
Kazuhiro Okada, Satoru Nakamura, Kiyonori Nagasaki, "Rubi as a Text: A Note on the Ruby Gloss Encoding," Journal of the Text Encoding Initiative, Issue 14, published online 2023-02-14, accessed 2026-10-23. https://doi.org/10.4000/jtei.4403 ↩ ↩2
-
GitHub Docs, "REST API endpoints for Markdown" (
POST /markdown,gfmmode), test run 2026-10-23, accessed 2026-10-23. https://docs.github.com/en/rest/markdown/markdown ↩ ↩2 ↩3 ↩4 -
Richard Ishida, "Ruby Markup," W3C Internationalization, first published 2016-06-14, updated 2026-04-24, accessed 2026-10-23. https://www.w3.org/International/articles/ruby/markup ↩ ↩2 ↩3 ↩4
-
青空文庫 (Aozora Bunko), 注記一覧 その他, "ルビとルビのように付く文字," accessed 2026-10-23. https://www.aozora.gr.jp/annotation/etc.html ↩ ↩2 ↩3 ↩4
-
Internet Archive, capture of the DenDenMarkdown syntax page, 2013-02-18. https://web.archive.org/web/20130218045010/http://conv.denshochan.com/markdown ↩
-
markdown-it-ruby README, GitHub, accessed 2026-10-23 (npm package created 2017-09-29 per https://registry.npmjs.org/markdown-it-ruby). https://github.com/lostandfound/markdown-it-ruby ↩
-
Steven Kraft, Markdown Furigana (Obsidian plugin) README, GitHub, accessed 2026-10-23. https://github.com/steven-kraft/obsidian-markdown-furigana ↩ ↩2
-
電書ちゃんねる, DenDenMarkdown (でんでんマークダウン) syntax, "ルビ," accessed 2026-10-23. https://conv.denshochan.com/markdown ↩ ↩2
-
k-quels, Japanese Novel Ruby (Obsidian plugin) README, "Limitations," accessed 2026-10-23. https://github.com/k-quels/japanese-novel-ruby ↩ ↩2
-
iltrof, furigana-markdown-it README, GitHub, accessed 2026-10-23. https://github.com/iltrof/furigana-markdown-it ↩
-
The Unicode Consortium, The Unicode Standard, Version 18.0, Chapter 23, §23.8.3 "Annotation Characters," accessed 2026-10-23. https://www.unicode.org/versions/Unicode18.0.0/core-spec/chapter-23/ ↩
-
W3C Japanese Language Enablement Task Force, Requirements for Japanese Text Layout, W3C Working Group Note, 11 August 2020, accessed 2026-10-23. https://www.w3.org/TR/jlreq/ ↩
-
Anthony Fu, Furifont README, GitHub, accessed 2026-10-23. https://github.com/antfu/furifont ↩ ↩2
-
Fumikazu Sato, Naoki Yoshinaga, Masaru Kitsuregawa, "Building Large-Scale Japanese Pronunciation-Annotated Corpora for Reading Heteronymous Logograms," Proceedings of LREC 2022, pp. 7113–7121, accessed 2026-10-23. http://www.lrec-conf.org/proceedings/lrec2022/pdf/2022.lrec-1.770.pdf ↩ ↩2