Text that always fits perfectly.
Typefit is a browser-first text fitting library powered by
@chenglou/pretext. It gives you a small React component,
a React hook, a DOM API, and a pure measurement API for fitting text into real layout constraints.
It is built for cases where simple DOM scaling is not enough: balanced multiline headlines, minimum and maximum line budgets, shaped rows, snapped type scales, custom font loading, and measurable layout results.
| Package | Purpose |
|---|---|
@typefit/react |
React component and hook. Install this in React apps. |
@typefit/core |
Framework-agnostic DOM and measurement APIs. |
bun add @typefit/reactnpm install @typefit/reactFor non-React projects:
bun add @typefit/coreimport { Typefit } from '@typefit/react';
export function HeroTitle() {
return (
<Typefit as="h1" maxSize={96} lines={{ min: 2 }} hideUntilFit>
Text that always fits perfectly.
</Typefit>
);
}Typefit reads normal CSS from the element, including custom fonts:
@font-face {
font-family: "Open Runde";
src: url("/fonts/OpenRunde-Semibold.woff2") format("woff2");
font-weight: 600;
font-style: normal;
font-display: swap;
}
.headline {
font-family: "Open Runde", system-ui, sans-serif;
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.05;
}<Typefit as="h1" className="headline" maxSize={112} lines={{ target: 2 }}>
Custom fonts work through CSS.
</Typefit>You can also pass the measured font explicitly:
const headlineFont = (size: number) =>
`600 ${size}px "Open Runde", system-ui, -apple-system, sans-serif`;
<Typefit as="h1" font={headlineFont} maxSize={112}>
Explicit font measurement.
</Typefit>;Use fitText when you want a pure measurement result before touching the DOM:
import { fitText } from '@typefit/core';
const result = fitText({
text: 'Balanced responsive text',
width: 520,
maxSize: 96,
lines: { target: 2, max: 3 },
balance: { mode: 'even' },
font: { family: 'Inter', weight: 700 },
includeLines: true,
});
console.log(result.fontSize, result.lineCount, result.lines);Use typefit when you want Typefit to measure an element, apply styles, and keep it updated:
import { typefit } from '@typefit/core';
const fit = typefit(element, {
maxSize: 96,
lines: { min: 2 },
observe: true,
});
fit.refresh();
fit.update({ shape: 'diamond' });
fit.destroy();Use lines to describe how many lines are acceptable.
<Typefit lines={{ min: 2, target: 3, max: 4 }}>
Fit this headline into a predictable line budget.
</Typefit>minasks Typefit to use at least this many lines.targetasks Typefit to prefer a specific line count.maxprevents Typefit from exceeding a line count.
If no max is provided, text may wrap to as many lines as needed. If a configured minSize
makes the requested fit impossible, the result reports fits: false.
<Typefit strategy="balance">Balanced wrapping.</Typefit>
<Typefit strategy="fill">Largest possible type.</Typefit>balancechooses a wrap that reads evenly, then sizes.fillprioritizes the largest font size that fits the container.
<Typefit balance={{ mode: 'even' }}>Even lines.</Typefit>
<Typefit balance={{ mode: 'compact' }}>Packed lines.</Typefit>
<Typefit balance={{ mode: 'stable', stability: 0.45 }}>Stable resize behavior.</Typefit>Use snap to keep fitted type on a design-system scale.
<Typefit snap={[24, 32, 40, 48, 56, 64, 72, 88, 104, 120]}>
Snap to intentional sizes.
</Typefit>Shape presets turn lines into strict row-width budgets.
<Typefit shape="diamond" lines={{ min: 3 }}>
Widest in the middle.
</Typefit>
<Typefit shape="pyramid" lines={{ min: 3 }}>
Wider every line.
</Typefit>Available presets:
'rectangle'
'pyramid'
'inverted-pyramid'
'diamond'
'hourglass'
'oval'
'left-ramp'
'right-ramp'Custom row shapes are supported too:
fitText({
text: 'Custom row offsets',
width: 360,
lines: { min: 3 },
shape: {
unit: 'ratio',
rows: [
{ width: 0.42, x: 0.29 },
{ width: 1, x: 0 },
{ width: 0.5, x: 0.25 },
],
},
font: { family: 'Inter', weight: 700 },
});<Typefit avoidWidows lastLine={{ minRatio: 0.3 }}>
Avoid a short final line when possible.
</Typefit>Typefit works in any current browser with standard canvas text measurement. It uses
OffscreenCanvas when available and falls back to a DOM canvas context, so Chromium, Firefox,
WebKit/Safari, and other standards-compliant browsers are supported.
Server-only measurement is not yet a V1 target.
The DOM and React APIs also listen for:
ResizeObserverMutationObserverdocument.fonts.readydocument.fontsloadingdone
When web fonts finish loading, Typefit clears cached metrics and refits.
| Export | Description |
|---|---|
Typefit |
Polymorphic React component. |
useTypefit |
Hook returning { ref, result, refresh }. |
const { ref, result, refresh } = useTypefit<HTMLHeadingElement>({
maxSize: 96,
lines: { target: 2 },
});
return <h1 ref={ref}>Measured with a hook</h1>;| Export | Description |
|---|---|
fitText(options) |
Pure measurement API. Requires text, width, and font. |
typefit(element, options) |
DOM fitting API. Reads text and computed styles from the element. |
isSupported() |
Returns whether the current browser can measure text. |
clearCache() |
Clears Pretext measurement cache. |
setLocale(locale?) |
Sets Pretext segmentation locale. |
| Option | Default | Description |
|---|---|---|
minSize |
10 |
Smallest font size Typefit may choose. |
maxSize |
512 |
Largest font size Typefit may choose. |
lines |
none | { min, target, max } line-count policy. |
strategy |
'balance' |
'balance' or 'fill'. |
balance |
{ mode: 'even' } |
Wrap scoring options. |
shape |
none | Shape preset or custom row configuration. |
snap |
none | Array of allowed font sizes, or { sizes, mode }. |
lastLine |
none | Final-line quality constraints. |
avoidWidows |
false |
Shortcut for avoiding short final lines. |
lineHeight |
1.1 |
Line-height multiplier or size callback. |
letterSpacing |
computed style | Letter spacing in pixels. |
observe |
true |
DOM/React only. Refit on resize, content changes, and font loads. |
hideUntilFit |
false |
React only. Hide until the first fit completes. |
We would love to have your help in making Typefit better.
Here's how you can contribute:
- Report a bug you found while using Typefit
- Request a feature that you think would be useful
- Submit a pull request if you want to contribute with new features or bug fixes
Typefit is licensed under the MIT License.