3.0.1 • Published 4 years ago
@flyyer/use-fit-text v3.0.1
@flyyer/use-fit-text
React hook that iteratively adjusts the font size so that text will fit in a div.
- checks if text is overflowing by using
scrollHeightandoffsetHeight - recalculates when container is resized (using (polyfilled)
ResizeObserver) - recalculates when content changes
- uses binary search; with default options, makes a maximum of 5 adjustments with a resolution of 5% font size from 20-100%
- < 4 kB minified + gzipped
- written in TypeScript
Installation
This module is meant for Flyyer.io templates to generate dynamic og:images for your links. But you can use it in other projects if it fits your needs.
yarn add @flyyer/use-fit-textUsage
import React from "react";
import clsx from "clsx";
import useFitText from "@flyyer/use-fit-text";
// Example for a flyyer.io template: $ npm create flyyer-app
export default function ExampleTemplate({ variables }) {
const title = variables["title"];
const description = variables["description"];
// UI-dependent variables (title and description) are added to the hook's dependency array.
const { fontSize, ref, isCalculating } = useFitText(
{
/** Depends on body's fontSize (usually 16px) */
maxFontSize: 1000, // 1000%
/** Lower values are more strict but causes more renders, defaults to `5` */
resolution: 10,
},
[title, description],
);
const className = clsx({ "flyyer-wait": isCalculating }) // use class flyyer-wait to prevent eager renders of flyyer templates.
return (
<div ref={ref} style={{ fontSize, height: 40, width: 100 }} className={className}>
<h1 style={{ fontSize: "2em" }}>
{title}
</h1>
<p style={{ fontSize: "1.2em" }}>
{description}
</p>
</div>
);
}If your text also depends on other style variables such as fontFamily, letterSpacing, etc; you should add them to the dependency array:
const title = variables["title"];
const fontFamily = variables["fontFamily"];
const { fontSize, ref, isCalculating } = useFitText({}, [title, fontFamily, letterSpacing]);
// ...About
This project is a fork from saltycrane/use-fit-text.
The main difference is:
- The original project depends on the
innerHTMLof therefelement to check for changes. - This fork has an explicit dependency array (same concept as
useEffect(, [dependencies])).
The main benefic is explicit control and easier to trigger re-calculations.
API
useFitText(options)
- Returns an object with the following properties:
fontSize(string) - the font size as a string (CSS percent) to be passed as thefontSizeproperty of thestyleprop of thedivref(React.MutableRefObject<HTMLDivElement>) - the ref to be passed to therefattribute of thediv
options(optional) - an object with the following optional properties:logLevel(string, default:info) - one ofdebug,info,warn,error, ornonemaxFontSize(number, default:100) - maximum font size in percentminFontSize(number, default:20) - minimum font size in percentonFinish((fontSize: number) => void, default:undefined) - function that is called when resizing finishes. The final fontSize is passed to the function as an argument.onStart(() => void, default:undefined) - function that is called when resizing startsresolution(number, default:5) - font size resolution to adjust to in percent
Questions
- Why doesn't it work with Flexbox
justify-content: flex-end;? This appears to be a bug with Flexbox. Try using CSS Grid ormargin-top: auto; - What does the "reached
minFontSize = 20without fitting text" message in the console mean? This meansuse-fit-textwas not able to fit the text using theminFontSizesetting of 20. To ensure the text fits, setminFontSizeto a smaller value.