├── examples ├── .gitignore ├── next-env.d.ts ├── README.md ├── next.config.js ├── tsconfig.json ├── package.json ├── bin │ └── gh-pages └── pages │ └── index.tsx ├── dist ├── examples │ └── pages │ │ └── index.d.ts ├── index.d.ts ├── index.modern.js ├── index.mjs ├── index.js ├── index.esm.js ├── index.umd.js ├── index.esm.js.map ├── index.modern.js.map ├── index.js.map ├── index.mjs.map └── index.umd.js.map ├── .gitignore ├── package.json ├── README.md └── index.ts /examples/.gitignore: -------------------------------------------------------------------------------- 1 | out -------------------------------------------------------------------------------- /examples/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /dist/examples/pages/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /** 3 | * Page 4 | */ 5 | declare function Page(): JSX.Element; 6 | export default Page; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .log 2 | .next 3 | .rpt2_cache 4 | .rts2_cache_cjs 5 | .rts2_cache_es 6 | .rts2_cache_umd 7 | node_modules 8 | package-lock.json 9 | !examples/package-lock.json -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # use-fit-text example 2 | 3 | ## Usage 4 | 5 | ``` 6 | npm install 7 | npm run dev 8 | ``` 9 | 10 | Go to http://localhost:3000 in the browser. Edit code in [`examples/pages/index.tsx`](/examples/pages/index.tsx) 11 | -------------------------------------------------------------------------------- /examples/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // set base path for github pages deploy 3 | // https://nextjs.org/docs/api-reference/next.config.js/basepath 4 | basePath: process.env.NODE_ENV === "production" ? "/use-fit-text" : "", 5 | }; 6 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare type TLogLevel = "debug" | "info" | "warn" | "error" | "none"; 3 | export declare type TOptions = { 4 | logLevel?: TLogLevel; 5 | maxFontSize?: number; 6 | minFontSize?: number; 7 | onFinish?: (fontSize: number) => void; 8 | onStart?: () => void; 9 | resolution?: number; 10 | }; 11 | declare const useFitText: ({ logLevel: logLevelOption, maxFontSize, minFontSize, onFinish, onStart, resolution, }?: TOptions) => { 12 | fontSize: string; 13 | ref: import("react").MutableRefObject; 14 | }; 15 | export default useFitText; 16 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve" 20 | }, 21 | "exclude": [ 22 | "node_modules" 23 | ], 24 | "include": [ 25 | "next-env.d.ts", 26 | "**/*.ts", 27 | "**/*.tsx" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-fit-text-example", 3 | "scripts": { 4 | "build": "NODE_ENV=production rm -rf node_modules/.cache && rm -rf .next/ && rm -rf out/ && next build && next export && touch out/.nojekyll", 5 | "deploy": "./bin/gh-pages", 6 | "dev": "next", 7 | "start": "next start", 8 | "tsc": "tsc --version && tsc" 9 | }, 10 | "prettier": { 11 | "trailingComma": "all" 12 | }, 13 | "dependencies": { 14 | "@types/node": "^14.10.1", 15 | "@types/react": "^16.9.49", 16 | "@types/react-dom": "^16.9.8", 17 | "next": "^9.5.3", 18 | "react": "^16.13.1", 19 | "react-dom": "^16.13.1", 20 | "typescript": "^4.0.2", 21 | "use-fit-text": "2.4.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-fit-text", 3 | "version": "2.4.0", 4 | "description": "React hook used to fit text in a div", 5 | "author": "saltycrane", 6 | "license": "MIT", 7 | "source": "index.ts", 8 | "main": "dist/index.js", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/saltycrane/use-fit-text.git" 12 | }, 13 | "keywords": [ 14 | "react", 15 | "fit", 16 | "text" 17 | ], 18 | "scripts": { 19 | "build": "microbundle" 20 | }, 21 | "prettier": { 22 | "trailingComma": "all" 23 | }, 24 | "peerDependencies": { 25 | "react": ">=16.8.0" 26 | }, 27 | "dependencies": { 28 | "resize-observer-polyfill": "^1.5.1" 29 | }, 30 | "devDependencies": { 31 | "@types/react": "^16.9.49", 32 | "microbundle": "^0.12.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/bin/gh-pages: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # forked from https://gist.github.com/motemen/8595451 4 | 5 | set -eux 6 | 7 | remote=$(git config remote.origin.url) 8 | described_rev=$(git rev-parse HEAD | git name-rev --stdin) 9 | 10 | pages_dir="./out" 11 | 12 | if [ ! -d "$pages_dir" ] 13 | then 14 | echo "Error: $pages_dir directory does not exist" 15 | exit 1 16 | fi 17 | 18 | cd "$pages_dir" 19 | 20 | cdup=$(git rev-parse --show-cdup) 21 | if [ "$cdup" != '' ] 22 | then 23 | git init 24 | git config user.email saltycrane@gmail.com 25 | git remote add --fetch origin "$remote" 26 | fi 27 | 28 | # delete gh-pages branch because got: 29 | # error: The following untracked working tree files would be overwritten by checkout: 30 | # git branch -D gh-pages 31 | git push origin --delete gh-pages 32 | 33 | if git rev-parse --verify origin/gh-pages > /dev/null 2>&1 34 | then 35 | git checkout gh-pages 36 | else 37 | git checkout --orphan gh-pages 38 | fi 39 | 40 | git add . 41 | git commit -m "github pages built at $described_rev" 42 | git push origin gh-pages 43 | -------------------------------------------------------------------------------- /dist/index.modern.js: -------------------------------------------------------------------------------- 1 | import{useCallback as e,useRef as n,useState as t,useEffect as r,useLayoutEffect as i}from"react";import o from"resize-observer-polyfill";const c="undefined"!=typeof window&&window.document&&window.document.createElement?i:r;export default({maxFontSize:i=100,minFontSize:f=20,onFinish:u,onStart:a,resolution:l=5}={})=>{const z=e(()=>({calcKey:0,fontSize:i,fontSizePrev:f,fontSizeMax:i,fontSizeMin:f}),[i,f]),S=n(null),s=n(),m=n(!1),[d,w]=t(z),{calcKey:M,fontSize:h,fontSizeMax:x,fontSizeMin:y,fontSizePrev:F}=d;let v=null;const[K]=t(()=>new o(()=>{v=window.requestAnimationFrame(()=>{m.current||(a&&a(),m.current=!0,w({...z(),calcKey:M+1}))})}));r(()=>(S.current&&K.observe(S.current),()=>{v&&window.cancelAnimationFrame(v),K.disconnect()}),[v,K]);const p=S.current&&S.current.innerHTML;return r(()=>{0===M||m.current||(p!==s.current&&(a&&a(),w({...z(),calcKey:M+1})),s.current=p)},[M,z,p,a]),c(()=>{if(0===M)return;const e=Math.abs(h-F)<=l,n=!!S.current&&(S.current.scrollHeight>S.current.offsetHeight||S.current.scrollWidth>S.current.offsetWidth),t=h>F;if(e)return void(n&&h===F?(m.current=!1,console.error(`Failed to fit text with \`minFontSize = ${f}\`. To fix, reduce \`minFontSize\`.`)):n?w({fontSize:t?F:y,fontSizeMax:x,fontSizeMin:y,fontSizePrev:F,calcKey:M}):(m.current=!1,u&&u(h)));let r,i=x,o=y;n?(r=t?F-h:y-h,i=Math.min(x,h)):(r=t?x-h:F-h,o=Math.max(y,h)),w({calcKey:M,fontSize:h+r/2,fontSizeMax:i,fontSizeMin:o,fontSizePrev:h})},[M,h,x,y,F,u,S,l]),{fontSize:h+"%",ref:S}}; 2 | //# sourceMappingURL=index.modern.js.map 3 | -------------------------------------------------------------------------------- /dist/index.mjs: -------------------------------------------------------------------------------- 1 | import{useCallback as n,useEffect as e,useLayoutEffect as t,useRef as r,useState as i}from"react";import o from"resize-observer-polyfill";var c={debug:10,info:20,warn:30,error:40,none:100},f="undefined"!=typeof window&&window.document&&window.document.createElement?t:e;export default function(t){void 0===t&&(t={});var u=t.logLevel;void 0===u&&(u="info");var a=t.maxFontSize;void 0===a&&(a=100);var l=t.minFontSize;void 0===l&&(l=20);var v=t.onFinish,z=t.onStart,S=t.resolution;void 0===S&&(S=5);var d=c[u],s=n(function(){return{calcKey:0,fontSize:a,fontSizePrev:l,fontSizeMax:a,fontSizeMin:l}},[a,l]),m=r(null),w=r(),M=r(!1),h=i(s),x=h[0],y=h[1],g=x.calcKey,b=x.fontSize,F=x.fontSizeMax,K=x.fontSizeMin,p=x.fontSizePrev,P=null,H=i(function(){return new o(function(){P=window.requestAnimationFrame(function(){M.current||(z&&z(),M.current=!0,y(Object.assign({},s(),{calcKey:g+1})))})})})[0];e(function(){return m.current&&H.observe(m.current),function(){P&&window.cancelAnimationFrame(P),H.disconnect()}},[P,H]);var j=m.current&&m.current.innerHTML;return e(function(){0===g||M.current||(j!==w.current&&(z&&z(),y(Object.assign({},s(),{calcKey:g+1}))),w.current=j)},[g,s,j,z]),f(function(){if(0!==g){var n=Math.abs(b-p)<=S,e=!!m.current&&(m.current.scrollHeight>m.current.offsetHeight||m.current.scrollWidth>m.current.offsetWidth),t=b>p;if(n)e&&b===p?(M.current=!1,d<=c.info&&console.info("[use-fit-text] reached `minFontSize = "+l+"` without fitting text")):e?y({fontSize:t?p:K,fontSizeMax:F,fontSizeMin:K,fontSizePrev:p,calcKey:g}):(M.current=!1,v&&v(b));else{var r,i=F,o=K;e?(r=t?p-b:K-b,i=Math.min(F,b)):(r=t?F-b:p-b,o=Math.max(K,b)),y({calcKey:g,fontSize:b+r/2,fontSizeMax:i,fontSizeMin:o,fontSizePrev:b})}}},[g,b,F,K,p,v,m,S]),{fontSize:b+"%",ref:m}} 2 | //# sourceMappingURL=index.mjs.map 3 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | var e,n=require("react"),t=(e=require("resize-observer-polyfill"))&&"object"==typeof e&&"default"in e?e.default:e,r={debug:10,info:20,warn:30,error:40,none:100},i="undefined"!=typeof window&&window.document&&window.document.createElement?n.useLayoutEffect:n.useEffect;module.exports=function(e){void 0===e&&(e={});var o=e.logLevel;void 0===o&&(o="info");var c=e.maxFontSize;void 0===c&&(c=100);var f=e.minFontSize;void 0===f&&(f=20);var u=e.onFinish,a=e.onStart,s=e.resolution;void 0===s&&(s=5);var l=r[o],S=n.useCallback(function(){return{calcKey:0,fontSize:c,fontSizePrev:f,fontSizeMax:c,fontSizeMin:f}},[c,f]),d=n.useRef(null),v=n.useRef(),z=n.useRef(!1),m=n.useState(S),w=m[0],M=m[1],h=w.calcKey,y=w.fontSize,x=w.fontSizeMax,b=w.fontSizeMin,g=w.fontSizePrev,F=null,K=n.useState(function(){return new t(function(){F=window.requestAnimationFrame(function(){z.current||(a&&a(),z.current=!0,M(Object.assign({},S(),{calcKey:h+1})))})})})[0];n.useEffect(function(){return d.current&&K.observe(d.current),function(){F&&window.cancelAnimationFrame(F),K.disconnect()}},[F,K]);var E=d.current&&d.current.innerHTML;return n.useEffect(function(){0===h||z.current||(E!==v.current&&(a&&a(),M(Object.assign({},S(),{calcKey:h+1}))),v.current=E)},[h,S,E,a]),i(function(){if(0!==h){var e=Math.abs(y-g)<=s,n=!!d.current&&(d.current.scrollHeight>d.current.offsetHeight||d.current.scrollWidth>d.current.offsetWidth),t=y>g;if(e)n&&y===g?(z.current=!1,l<=r.info&&console.info("[use-fit-text] reached `minFontSize = "+f+"` without fitting text")):n?M({fontSize:t?g:b,fontSizeMax:x,fontSizeMin:b,fontSizePrev:g,calcKey:h}):(z.current=!1,u&&u(y));else{var i,o=x,c=b;n?(i=t?g-y:b-y,o=Math.min(x,y)):(i=t?x-y:g-y,c=Math.max(b,y)),M({calcKey:h,fontSize:y+i/2,fontSizeMax:o,fontSizeMin:c,fontSizePrev:y})}}},[h,y,x,b,g,u,d,s]),{fontSize:y+"%",ref:d}}; 2 | //# sourceMappingURL=index.js.map 3 | -------------------------------------------------------------------------------- /dist/index.esm.js: -------------------------------------------------------------------------------- 1 | import{useCallback as n,useRef as e,useState as t,useEffect as r,useLayoutEffect as i}from"react";import o from"resize-observer-polyfill";function c(){return(c=Object.assign||function(n){for(var e=1;eh.current.offsetHeight||h.current.scrollWidth>h.current.offsetWidth),t=b>H;if(n)e&&b===H?(y.current=!1,console.error("Failed to fit text with `minFontSize = "+S+"`. To fix, reduce `minFontSize`.")):e?F({fontSize:t?H:g,fontSizeMax:P,fontSizeMin:g,fontSizePrev:H,calcKey:K}):(y.current=!1,d&&d(b));else{var r,i=P,o=g;e?(r=t?H-b:g-b,i=Math.min(P,b)):(r=t?P-b:H-b,o=Math.max(g,b)),F({calcKey:K,fontSize:b+r/2,fontSizeMax:i,fontSizeMin:o,fontSizePrev:b})}}},[K,b,P,g,H,d,h,m]),{fontSize:b+"%",ref:h}} 2 | //# sourceMappingURL=index.esm.js.map 3 | -------------------------------------------------------------------------------- /dist/index.umd.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("react"),require("resize-observer-polyfill")):"function"==typeof define&&define.amd?define(["react","resize-observer-polyfill"],n):e.useFitText=n(e.react,e.ResizeObserver)}(this,function(e,n){n=n&&n.hasOwnProperty("default")?n.default:n;var t={debug:10,info:20,warn:30,error:40,none:100},r="undefined"!=typeof window&&window.document&&window.document.createElement?e.useLayoutEffect:e.useEffect;return function(i){void 0===i&&(i={});var o=i.logLevel;void 0===o&&(o="info");var f=i.maxFontSize;void 0===f&&(f=100);var c=i.minFontSize;void 0===c&&(c=20);var u=i.onFinish,a=i.onStart,s=i.resolution;void 0===s&&(s=5);var l=t[o],d=e.useCallback(function(){return{calcKey:0,fontSize:f,fontSizePrev:c,fontSizeMax:f,fontSizeMin:c}},[f,c]),v=e.useRef(null),z=e.useRef(),S=e.useRef(!1),m=e.useState(d),w=m[0],y=m[1],h=w.calcKey,M=w.fontSize,x=w.fontSizeMax,b=w.fontSizeMin,p=w.fontSizePrev,g=null,F=e.useState(function(){return new n(function(){g=window.requestAnimationFrame(function(){S.current||(a&&a(),S.current=!0,y(Object.assign({},d(),{calcKey:h+1})))})})})[0];e.useEffect(function(){return v.current&&F.observe(v.current),function(){g&&window.cancelAnimationFrame(g),F.disconnect()}},[g,F]);var K=v.current&&v.current.innerHTML;return e.useEffect(function(){0===h||S.current||(K!==z.current&&(a&&a(),y(Object.assign({},d(),{calcKey:h+1}))),z.current=K)},[h,d,K,a]),r(function(){if(0!==h){var e=Math.abs(M-p)<=s,n=!!v.current&&(v.current.scrollHeight>v.current.offsetHeight||v.current.scrollWidth>v.current.offsetWidth),r=M>p;if(e)n&&M===p?(S.current=!1,l<=t.info&&console.info("[use-fit-text] reached `minFontSize = "+c+"` without fitting text")):n?y({fontSize:r?p:b,fontSizeMax:x,fontSizeMin:b,fontSizePrev:p,calcKey:h}):(S.current=!1,u&&u(M));else{var i,o=x,f=b;n?(i=r?p-M:b-M,o=Math.min(x,M)):(i=r?x-M:p-M,f=Math.max(b,M)),y({calcKey:h,fontSize:M+i/2,fontSizeMax:o,fontSizeMin:f,fontSizePrev:M})}}},[h,M,x,b,p,u,v,s]),{fontSize:M+"%",ref:v}}}); 2 | //# sourceMappingURL=index.umd.js.map 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # use-fit-text [![npm version](https://badge.fury.io/js/use-fit-text.svg)](https://badge.fury.io/js/use-fit-text) 2 | 3 | React hook that iteratively adjusts the font size so that text will fit in a div. 4 | 5 | - checks if text is overflowing by [using `scrollHeight` and `offsetHeight`](https://stackoverflow.com/a/10017343/101911) 6 | - recalculates when container is resized (using ([polyfilled](https://github.com/que-etc/resize-observer-polyfill)) [`ResizeObserver`](https://developers.google.com/web/updates/2016/10/resizeobserver)) 7 | - recalculates when content changes 8 | - uses binary search; with default options, makes a maximum of 5 adjustments with a resolution of 5% font size from 20-100% 9 | - [< 4 kB](https://bundlephobia.com/result?p=use-fit-text@2.4.0) minified + gzipped 10 | - written in TypeScript 11 | 12 | ## Installation 13 | 14 | ``` 15 | npm install --save use-fit-text 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```js 21 | import React from "react"; 22 | import useFitText from "use-fit-text"; 23 | 24 | function Example() { 25 | const { fontSize, ref } = useFitText(); 26 | 27 | return ( 28 |
29 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 30 |
31 | ); 32 | } 33 | ``` 34 | 35 | ## Demo / example code 36 | 37 | - Demo site: https://saltycrane.github.io/use-fit-text/ 38 | - [Example code](/examples/pages/index.tsx) is in the `/examples` folder 39 | 40 | ## API 41 | 42 | ### `useFitText(options)` 43 | - Returns an object with the following properties: 44 | - `fontSize` (`string`) - the font size as a string (CSS percent) to be passed as the `fontSize` property of the `style` prop of the `div` 45 | - `ref` (`React.MutableRefObject`) - the ref to be passed to the `ref` attribute of the `div` 46 | - `options` (optional) - an object with the following optional properties: 47 | 48 | - `logLevel` (`string`, default: `info`) - one of `debug`, `info`, `warn`, `error`, or `none` 49 | - `maxFontSize` (`number`, default: `100`) - maximum font size in percent 50 | - `minFontSize` (`number`, default: `20`) - minimum font size in percent 51 | - `onFinish` (`(fontSize: number) => void`, default: `undefined`) - function that is called when resizing 52 | finishes. The final fontSize is passed to the function as an argument. 53 | - `onStart` (`() => void`, default: `undefined`) - function that is called when resizing starts 54 | - `resolution` (`number`, default: `5`) - font size resolution to adjust to in percent 55 | 56 | ## Questions 57 | 58 | - Why doesn't it work with Flexbox `justify-content: flex-end;`? 59 | This appears [to be](https://stackoverflow.com/questions/36130760/use-justify-content-flex-end-and-to-have-vertical-scrollbar) [a bug](https://github.com/philipwalton/flexbugs/issues/53) with Flexbox. Try using CSS Grid or `margin-top: auto;` 60 | - What does the "reached `minFontSize = 20` without fitting text" message in the console mean? 61 | 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. 62 | 63 | ## Changelog 64 | 65 | - v2.4.0 66 | - 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. 67 | - fix final adjustment calcuation 68 | - add `logLevel` option to control what is logged to the console 69 | - v2.3.0 70 | - automatically recalculate font size when content changes 71 | - fix bug where a recalculation was not done on resize if the text initially fit in the div 72 | - v2.2.0 - add `onStart` and `onFinish` callbacks 73 | - v2.1.3 - export `TOptions` TypeScript type 74 | - v2.1.2 - remove `/// ` in `dist/index.d.ts` 75 | - v2.1.0 76 | - fix SSR/prerender issue where text did not resize 77 | - suppress `useLayoutEffect` warning for server render 78 | - v2.0.0 79 | - use `ResizeObserver` to always recalculate on container resize 80 | - remove `recalcOnResize` option 81 | - `useLayoutEffect` instead of `useEffect` to avoid flashing 82 | - v1.2.1 - fix scrollbar issue in example 83 | - v1.2.0 - add `recalcOnResize` and other options 84 | - v1.1.0 - fix binary search bug 85 | - v1.0.2 - add example 86 | - v1.0.0 - initial release 87 | -------------------------------------------------------------------------------- /examples/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import React, { useCallback, useState } from "react"; 3 | import useFitText from "use-fit-text"; 4 | 5 | /** 6 | * Example1 - basic example 7 | */ 8 | function Example1() { 9 | const { fontSize, ref } = useFitText(); 10 | return ( 11 | <> 12 | Example 1 - basic example 13 |
17 | Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, 18 | consectetur 19 |
20 |
21 | 22 | ); 23 | } 24 | 25 | /** 26 | * Example2 - non-wrapping text 27 | */ 28 | function Example2() { 29 | const { fontSize, ref } = useFitText(); 30 | return ( 31 | <> 32 | Example 2 - non-wrapping text 33 |
37 |
38 | Lorem ipsum dolor sit amet, consectetur 39 |
40 |
41 |
42 | 43 | ); 44 | } 45 | 46 | /** 47 | * Example3 - demonstrates: 48 | * - recalculating font size on window resize 49 | * - `onStart` and `onFinish` callbacks 50 | */ 51 | function Example3() { 52 | const onStart = useCallback(() => { 53 | console.log("Example 3 resizing started"); 54 | }, []); 55 | const onFinish = useCallback((fontSize: number) => { 56 | console.log("Example 3 resizing finished", fontSize); 57 | }, []); 58 | const { fontSize, ref } = useFitText({ maxFontSize: 500, onStart, onFinish }); 59 | 60 | return ( 61 | <> 62 | Example 3 - recalculating on container change 63 |

Demonstrates:

64 |
    65 |
  • recalculating font size on window resize
  • 66 |
  • 67 | onStart and{" "} 68 | onFinish callbacks (see log message 69 | in the console) 70 |
  • 71 |
72 |
80 | Lorem ipsum dolor sit amet, consectetur 81 |
82 |
83 | 84 | ); 85 | } 86 | 87 | /** 88 | * Example4 - recalculating on content change 89 | */ 90 | function Example4() { 91 | const [text, setText] = useState("Lorem ipsum dolor sit amet, consectetur"); 92 | const { fontSize, ref } = useFitText(); 93 | 94 | return ( 95 | <> 96 | Example 4 - recalculating on content change 97 |

98 | Change the input text and the font size will be updated to fit the text 99 | in the div 100 |

101 |
102 |