fitwidth

Fill any width,
exactly.

npm ↗
GitHub
TypeScript·Zero dependencies·React + Vanilla JS

CSS can't make a display headline fill its container — letter-spacing is proportional, and the wdth axis affects every character equally. Fit Width binary-searches both to converge on an exact width to within half a pixel.

Live demo — drag the slider

Container Width80%
Prefer

Typography

fvs: ls: 0em

Display Type

fvs: ls: 0em

Headline

fvs: ls: 0em

Each headline fills its container exactly — to within half a pixel. Drag the slider to resize the container. Switch prefer mode to see the wdth axis or letter-spacing used in isolation.

How it works

CSS can't fit a headline

letter-spacing adds a fixed amount after every character — it's proportional, not absolute. The wdth axis scales character shapes but doesn't guarantee a target width. Neither can converge on an exact measurement alone.

Binary search converges in 20 iterations

Fit Width uses a classic binary search: measure the element, compare to target, move the midpoint. Within 15–20 iterations it converges to within the tolerance (default 0.5 px). The cost is negligible — no reflow until the final write.

Axis first, then tracking

In prefer='auto' mode, Fit Width tries the wdth axis first. If the axis range isn't enough to reach the target, letter-spacing closes the remaining gap. Either strategy can be used exclusively via 'axis' or 'tracking'.

Idempotent — call it again on resize

Original inline styles are saved on the first call and restored before each re-fit. It's safe to call applyFitWidth repeatedly. useFitWidth and FitWidthText wire up a ResizeObserver and document.fonts.ready automatically.

Usage

TypeScript + React · Vanilla JS

Drop-in component

import { FitWidthText } from '@liiift-studio/fitwidth'

<FitWidthText prefer="auto">
  Display Headline
</FitWidthText>

Hook — attach to any element

import { useFitWidth } from '@liiift-studio/fitwidth'

const ref = useFitWidth({ prefer: 'auto' })
<h1 ref={ref}>Display Headline</h1>

Vanilla JS

import { applyFitWidth, removeFitWidth } from '@liiift-studio/fitwidth'

const el = document.querySelector('h1')
applyFitWidth(el, { prefer: 'auto' })

// Restore original styles
removeFitWidth(el)

Options

OptionDefaultDescription
target'container'Width to fill: 'container' (parent clientWidth), a pixel number, or an HTMLElement.
prefer'auto''auto' — wdth axis first, then letter-spacing. 'axis' — axis only. 'tracking' — letter-spacing only.
axis'wdth'Variable font axis tag to binary-search.
axisMin75Minimum axis value for the binary search.
axisMax125Maximum axis value for the binary search.
maxTracking0.3Maximum absolute letter-spacing in em (clamped to ±this value).
tolerance0.5Convergence tolerance in pixels — search stops when within this gap.
as'h1'HTML element to render. Accepts any valid React element type. (FitWidthText only)