React overview
glyphline/react, the GlyphOverlay component and hooks for React 18 and 19.
Every demo on this site is built with glyphline/react.
How the cursor moves
Along a line the cursor stretches toward the next word and then contracts onto it. Between lines it travels with the same motion, so going down a line reads like moving along it.
- A sentence is one rounded shape, even across lines.
- Justified line ends are snapped, so the edge stays straight.
Drag the corner of this box to change its width while it reads.
Install
bun add glyphline
# for PDF pages
bun add pdfjs-distThe React adapter ships inside glyphline as glyphline/react; React is an optional peer, so Svelte apps never install it. Import the stylesheet once:
import "glyphline/style.css";HTML in five lines
import { GlyphOverlay, useDomSource } from "glyphline/react";
import "glyphline/style.css";
export function Article({ word, sentence }: { word: number; sentence: number }) {
const [ref, source] = useDomSource<HTMLElement>();
return (
<div style={{ position: "relative" }}>
<article ref={ref}>
<p>Alice was beginning to get very tired of sitting by her sister on the bank…</p>
</article>
<GlyphOverlay source={source} sentence={sentence} word={word} />
</div>
);
}useDomSource returns a ref and the source for that element. The source is rebuilt when the element's text changes (React rendered new children), so word and sentence indices always match what is on screen. It is null until the element mounts; GlyphOverlay draws nothing until then.
Clicking a word
import { wordAtPoint } from "glyphline";
<div
style={{ position: "relative" }}
onClick={(e) => {
const svg = e.currentTarget.querySelector("svg.gl-overlay");
if (!source || !svg || !document.getSelection()?.isCollapsed) return;
const w = wordAtPoint(source, svg, e.clientX, e.clientY);
if (w >= 0) setWord(w);
}}
>The isCollapsed check keeps a drag (a text selection) from also moving the cursor.
Next.js
The package starts with "use client", so GlyphOverlay and the hooks work from a server component tree. Sources read the DOM or pdf.js, so they are only made in the browser; both hooks handle that.
Next
Made by Lucas Piera