A zero-dependency JavaScript library

قِفَا نَبْكِ مِنْ ذِكْرَى حَبِيبٍ وَمَنْزِلِ \ بِسِقْطِ اللِّوَى بَيْنَ الدَّخُولِ فَحَوْمَلِ

— Imruʾ al-Qais, the Muʿallaqa

Typeset Arabic, Urdu & Persian poetry —
laid out, balanced, and justified on the web.

Ashaar.js parses marked-up verse and renders proper RTL two-column couplets, stanzas, and refrains — then fills each hemistich to a single elegant width with real kashida.

0 dependencies ~19 KB core UMD · browser & Node 3 justification modes

Live playground

This is the library, running right here.

Edit the verse on the right-hand box. Every keystroke is parsed and typeset by Ashaar.js in real time. Switch the justification mode to watch kashida fill each line.

Input · marked-up verse
Output · typeset
Justify
Layout

Try it → cycle through None → CSS native → Kashida (tatweel) to compare how each mode fills the line. Kashida balances every misra to the longest line.

Syntax: \ splits a couplet · a bare line is a full-width solo misra · blank line = stanza · --- = new poem · trailing % marks a refrain.

What it does

Everything the line needs — and nothing it doesn't.

No framework, no build step, no runtime dependency. One script tag turns marked-up text into properly set verse.

١

Structural parsing

Couplets, solo misras, stanzas, poem breaks, and refrains from a tiny markup vocabulary — \, |, *, %, ---.

٢

RTL two-column layout

Sadr on the right, ajuz on the left, with a centred gap glyph — the canonical shape of the bayt, as flexbox.

٣

Real kashida justification

Inserts U+0640 tatweel by DOM measurement and binary search, honouring Arabic joining rules. Balances every misra to the longest line.

٤

Three justify modes

Off, CSS-native (text-justify), or measured kashida. A ResizeObserver re-runs kashida on container resize.

٥

Refrain & stacked styles

Colour refrains independently, or switch to stacked/indented layouts — all themeable through CSS custom properties.

٦

Browser & Node

UMD build works as a script tag or a require(). Render to live DOM with init() or to an HTML string with renderText().

Quick start

One stylesheet, one script, one call.

Browser · script tag
<link rel="stylesheet" href="stylesheet.css">

<div class="ashaar" data-ashaar>
  قِفَا نَبْكِ … \ بِسِقْطِ اللِّوَى …
</div>

<script src="ashaar-justify.js"></script>
<script src="ashaar.js"></script>
<script>
  Ashaar.init({ justify: 'kashida' });
</script>
Node · render to a string
const Ashaar = require('./ashaar.js');

const html = Ashaar.renderText(poem);
// → <div class="ashaar-poem">…</div>

// or post-process one element in the DOM:
Ashaar.justifyEl(el, { method: 'kashida' });

Same poetry · different platform

Writing in Microsoft Word?

The Ashaar Poetry Word add-in puts this same RTL layout and kashida justification engine inside Word — typeset poems into native tables and justify them in place.

Get the Word add-in ↗