Giter Club home page Giter Club logo

use-fit-text's Introduction

use-fit-text npm version

React hook that iteratively adjusts the font size so that text will fit in a div.

  • checks if text is overflowing by using scrollHeight and offsetHeight
  • 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

npm install --save use-fit-text

Usage

import React from "react";
import useFitText from "use-fit-text";

function Example() {
  const { fontSize, ref } = useFitText();

  return (
    <div ref={ref} style={{ fontSize, height: 40, width: 100 }}>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </div>
  );
}

Demo / example code

API

useFitText(options)

  • Returns an object with the following properties:

    • fontSize (string) - the font size as a string (CSS percent) to be passed as the fontSize property of the style prop of the div
    • ref (React.MutableRefObject<HTMLDivElement>) - the ref to be passed to the ref attribute of the div
  • options (optional) - an object with the following optional properties:

    • logLevel (string, default: info) - one of debug, info, warn, error, or none
    • maxFontSize (number, default: 100) - maximum font size in percent
    • minFontSize (number, default: 20) - minimum font size in percent
    • onFinish ((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 starts
    • resolution (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 or margin-top: auto;
  • What does the "reached minFontSize = 20 without fitting text" message in the console mean? This means use-fit-text was not able to fit the text using the minFontSize setting of 20. To ensure the text fits, set minFontSize to a smaller value.

Changelog

  • v2.4.0
    • handle case where minFontSize is set larger than the fontSize value needed to fit the text in the div. Log a message to the console in this case.
    • fix final adjustment calcuation
    • add logLevel option to control what is logged to the console
  • v2.3.0
    • automatically recalculate font size when content changes
    • fix bug where a recalculation was not done on resize if the text initially fit in the div
  • v2.2.0 - add onStart and onFinish callbacks
  • v2.1.3 - export TOptions TypeScript type
  • v2.1.2 - remove /// <reference types="next" /> in dist/index.d.ts
  • v2.1.0
    • fix SSR/prerender issue where text did not resize
    • suppress useLayoutEffect warning for server render
  • v2.0.0
    • use ResizeObserver to always recalculate on container resize
    • remove recalcOnResize option
    • useLayoutEffect instead of useEffect to avoid flashing
  • v1.2.1 - fix scrollbar issue in example
  • v1.2.0 - add recalcOnResize and other options
  • v1.1.0 - fix binary search bug
  • v1.0.2 - add example
  • v1.0.0 - initial release

use-fit-text's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

use-fit-text's Issues

Fill the whole width initially & 'text-align: center;' problem

Hi, Thanks for the package.

Is there a way to tell useFitText to fill the whole width initially?
I mean the fontSize should be determined based on parent width initially but it is always at 100%; (needed for large parent element width)
maybe a field in the options object passed to useFitText is needed; like:
{ ... initialFontSize: 200, // OR: initialFontSize: "full-width" }

And also while applying text-align: center;, the retrieved fontSize from useFitText is different from "not applying this style".

How to be sure that redraw is finished ?

I'm using puppeteer to print a page that need font to be resized. Not all of my font get's resized when printing the page... How can I be sure the page is done refiting my font ?

Cannot find type definition file for 'next'.

Hi, probably this is stupid question (sorry, but I'm not really good at Typescript).

But during the build or typescript project I'm getting this error:

node_modules/use-fit-text/dist/index.d.ts:2:23 - error TS2688: Cannot find type definition file for 'next'.

the question is, do you really need this line /// <reference types="next" /> in file dist/index.d.ts ?

Maximum update depth exceeded

The state is updated too much and the changes in font size are minuscule:
image

This happens when maxFontSize or minFontSize aren't integers (they probably should be rounded to up to 2 places or parsed as int)

We can get rid of the binary search in the font size algorithm

I read in the Readme that you are using binary search. It seems that performance can be improved by not using binary search.

The algorithm for finding the font size is as follows:

  1. get the width of the text const {width} = myElement. getBoundingClientRect();
  2. coefficient = element_width / fontSize
  3. to get the font size that will fit without breaking a line in a div with a width of 400 pixels, you need to divide 400 by this coefficient;
    newFontSize = 400 / coefficient
  4. ...
  5. Profit! :)

A working demo and code can be viewed here

and here you can look at this algorithm:

Consider removing polyfill

Hi,

I am here following up on an issue where I am migrating a CRA codebase to VITE.

It seems that there is an issue with rollup and the Resize Observer polyfill used.
TypeError: ResizeObserver constructor: 'new' is required
This has been reported in other libraries that use the polyfill and the answer has normally been to remove the polyfill.

Currently ResizeObserver API reaches 94.18% of the browsers.
No code changes needed other than removing the polyfill import

Happy to create a PR if you would like to move this forward

Support non-px width values?

Perhaps this is already a feature and I've just not had luck with it? I tried 100% and 100vw and the text fit functionality doesn't seem to work properly with either. I've gotten it working with px, which it what gets me thinking maybe other units aren't supported?

Thanks for an awesome project. This seems like a really promising React text-fit library!

Not resizing on the first rendering

@saltycrane thanks for your work with this hook. I've been testing it over Next.js (with SSG and SSR pages) but I can't get it to resize correctly when I render the page.

Everything works as soon as I resize the viewport, otherwise, I always get 100 for the font size. Do you think there is a way to trigger it manually? Do you have any idea why this might happen?

Initial render
CleanShot 2022-05-20 at 18 47 08

After resizing the viewport
CleanShot 2022-05-20 at 18 48 04

Initial fontSize value is not updated and onStart/onFinish do not fire

I'm not sure what the issue is, because we use useFitText in one other place and it works, but in this other circumstance it simply defaults to the specified maxFontSize, even if that means it wraps lines. It's the same whether we use a width specified in pixels or percentages, whether we set a height on the element, whether we set overflow: hidden - whether we change the text or resize the window. Nothing happens under any circumstances. Any thoughts?

Not resizing on dynamically received data

If the content of container is being changed dynamically then the hook does not recalculate the font size.

Looking back through the closed issues, I found this one, what says this was resolved back in v2.3.0 with the example given here example 4.

However, I am not convinced the solution solves the problem. While altering the text, the example does change the size of the font, but it does so using the previously rendered text, not the current text. This isn't obvious if you enter/delete using the provided text input, because the text is being resized to a similar number of characters. For example if your text is 20 characters long, adding another character will be it 21, and the font size calculation will happen on the original 20 which is close enough for it not to be a problem. So as you type the calculation is always done on the previous text, and so the problem appears to be resolved.

The problem becomes evident when the dynamic text is a different character length than the original. You can see the problem if you copy/paste characters into the input. See below
Screen Recording (Google Chrome)

Fails setting `lineHeight`

Not totally sure why but passing lineHeight to style causes it to always be minFontSize with the console error.

Any tips on how to get this working?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.