Skip to the text

Docs Start

Getting started

Install the package, typeset a string, then pick the mode that matches where your text lives. Everything below runs as it is written.

Install

The package is @mokhniuk/typography. It reaches npm with 1.0; until then it is a git dependency on a release tag. The repository is private, so the machine needs SSH access to it.

bun add git+ssh://git@github.com/mokhniuk/typography.git#v0.11.0

After 1.0 this becomes npm install @mokhniuk/typography (or pnpm add, bun add, yarn add). The package ships TypeScript sources and has no build step, so it needs Bun or a TypeScript-aware bundler. The core has no dependencies; react 18 or later is an optional peer, needed only by the React entry.

Typeset a string

import { typographic } from '@mokhniuk/typography';

typographic('He said "we\'re here" - and left.', 'en', { quoteStyle: 'us' });
// He said “we’re here” — and left.

The second argument is the language (en when you give none). The output is stable: a second run on it changes nothing, in every language.

English defaults to the package’s house guillemets «…». Pass quoteStyle: 'us' for “…” with ‘…’ inside, in any language. The literary register sets book-style marks where a language has them.

See what it changed

import { explain } from '@mokhniuk/typography';

explain('He said "hi"... 21-26', 'en', { quoteStyle: 'us' });
// { output: 'He said “hi”… 21–26', changes: [{ rule: 'quote', from: '"', to: '“' }, …] }

Every change names the rule behind it. Switch a rule off by its id, or a whole group (space, dash, symbol); rules that are off by default run only when named in enable. The rules page lists them all, and an unknown name throws, so a typo cannot pass for “everything stays on”.

typographic('21-26 - x', 'en', { disable: ['dash.range'] });
typographic('Call 1000000 , now', 'en', { enable: ['number.group', 'space.before-punctuation'] });

HTML, Markdown and pipelines

import { typesetHtml } from '@mokhniuk/typography/html';
import { typesetMarkdown } from '@mokhniuk/typography/markdown';

typesetHtml('<p>She said "go" - <a href="/x">Read more -></a></p>', { lang: 'en' });
typesetMarkdown('# "Title" - subtitle\n\n`a -> b` stays.', { lang: 'en' });

Tags, attributes, comments and the content of pre, code, script and style are left as they were. In a unified pipeline, use @mokhniuk/typography/rehype as a plugin. This website is built that way: every page you read went through typesetHtml.

React

import { Typeset, TypographyRoot } from '@mokhniuk/typography/react';

<TypographyRoot lang="uk">
  <p><Typeset text={'Він сказав "камінь" - і пішов'} /></p>
</TypographyRoot>

TypographyRoot also hangs opening and closing punctuation in the margin, and sends the small inline script that makes it right at first paint on a prerendered page.

Command line

typo note.txt                  # typeset to standard output
typo -w docs/*.md              # rewrite files in place
typo -c docs/*.md              # change nothing; exit 1 if any file would change (CI)

Where next

Something wrong or unclear here? Report an issue.