glyphline
React

React overview

glyphline/react, the GlyphOverlay component and hooks for React 18 and 19.

Every demo on this site is built with glyphline/react.

Inline markup, a heading and a list: one text for glyphline.

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-dist

The 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

On this page