react-detect-overflow 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rainymy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # react-detect-overflow
2
+
3
+ React hooks for detecting horizontal and vertical overflow on DOM elements. Reactively updates when the element is resized.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install react-detect-overflow
9
+ ```
10
+
11
+ ## Requirements
12
+
13
+ - React `v16.8.0` or later
14
+
15
+ ---
16
+
17
+ ## Usage
18
+
19
+ ### `useDetectOverflowX`
20
+
21
+ Detects horizontal overflow on an element.
22
+
23
+ ```tsx
24
+ import { useDetectOverflowX } from "react-detect-overflow";
25
+
26
+ function MyComponent() {
27
+ const { isOverflowing, amount, ratio, ref } =
28
+ useDetectOverflowX<HTMLDivElement>();
29
+
30
+ return (
31
+ <div ref={ref} style={{ width: 200, overflow: "hidden" }}>
32
+ {isOverflowing && <span>Overflowing by {amount}px</span>}
33
+ Some very long content that might overflow...
34
+ </div>
35
+ );
36
+ }
37
+ ```
38
+
39
+ ### `useDetectOverflowY`
40
+
41
+ Detects vertical overflow on an element.
42
+
43
+ ```tsx
44
+ import { useDetectOverflowY } from "react-detect-overflow";
45
+
46
+ function MyComponent() {
47
+ const { isOverflowing, amount, ratio, ref } =
48
+ useDetectOverflowY<HTMLDivElement>();
49
+
50
+ return (
51
+ <div ref={ref} style={{ height: 100, overflow: "hidden" }}>
52
+ {isOverflowing && <span>Overflowing by {amount}px</span>}
53
+ <p>Some very long content that might overflow vertically...</p>
54
+ </div>
55
+ );
56
+ }
57
+ ```
58
+
59
+ ### Using an external ref
60
+
61
+ If you already have a ref on the element, pass it in to avoid creating a second one.
62
+
63
+ ```tsx
64
+ import { useRef } from "react";
65
+ import { useDetectOverflowX } from "react-detect-overflow";
66
+
67
+ function MyComponent() {
68
+ const ref = useRef<HTMLDivElement>(null);
69
+ const { isOverflowing } = useDetectOverflowX(ref);
70
+
71
+ return <div ref={ref}>{isOverflowing && <span>Overflowing!</span>}</div>;
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ### Example usage with `ratio`
78
+
79
+ `ratio` is the `scrollSize / clientSize` of the element. A value of `1` means no overflow — values above `1` indicate how much larger the content is relative to the visible area. This can be used to drive animations or dynamic styles.
80
+
81
+ ```tsx
82
+ /**
83
+ * A text title that bounces when overflowing.
84
+ */
85
+ function BouncyTitle2({ title }) {
86
+ const { isOverflowing, amount, ratio, ref } =
87
+ useDetectOverflowX<HTMLDivElement>();
88
+
89
+ return (
90
+ <div ref={ref} className={"container"}>
91
+ <span
92
+ className={`text_content ${isOverflowing ? "bounce" : ""}`}
93
+ data-overflow={amount}
94
+ data-animation-duration={3 * ratio}
95
+ >
96
+ {title}
97
+ </span>
98
+ </div>
99
+ );
100
+ }
101
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,89 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let e = require("react");
3
+ //#region src/overflow.tsx
4
+ /**
5
+ * Base hook for detecting overflow on a DOM element given axis.
6
+ * Observes the element for size changes and recomputes overflow reactively.
7
+ *
8
+ * @param getSizes - A function that extracts scroll and client sizes from the element
9
+ * @param externRef - An optional external ref to attach to the element. If not provided, an internal ref is created.
10
+ * @returns An object containing overflow state and the ref to attach to the element
11
+ *
12
+ * @example
13
+ * // Custom axis (e.g. both dimensions summed)
14
+ * const { isOverflowing, ref } = useDetectOverflow(
15
+ * (el) => ({ scrollSize: el.scrollWidth, clientSize: el.clientWidth }),
16
+ * );
17
+ */
18
+ function t(t, n) {
19
+ let r = (0, e.useRef)(null), i = (0, e.useRef)(t), a = n ?? r;
20
+ (0, e.useLayoutEffect)(() => {
21
+ i.current = t;
22
+ }, [t]);
23
+ let [o, s] = (0, e.useState)(!1), [c, l] = (0, e.useState)(0), [u, d] = (0, e.useState)(0), f = (0, e.useCallback)((e) => {
24
+ let { scrollSize: t, clientSize: n } = i.current(e), r = t - n, a = n > 0 ? t / n : 0;
25
+ l(Math.max(0, r)), s(r > 0), d(a);
26
+ }, []);
27
+ return (0, e.useLayoutEffect)(() => {
28
+ let e = a.current;
29
+ if (!e) {
30
+ console.warn(`ref is not attached to React element: ${e}`);
31
+ return;
32
+ }
33
+ f(e);
34
+ let t = new ResizeObserver((e) => {
35
+ e[0] && f(e[0].target);
36
+ });
37
+ return t.observe(e), () => {
38
+ t.unobserve(e);
39
+ };
40
+ }, [a, f]), {
41
+ isOverflowing: o,
42
+ amount: c,
43
+ ratio: u,
44
+ ref: a
45
+ };
46
+ }
47
+ //#endregion
48
+ //#region src/index.tsx
49
+ /**
50
+ * Detects horizontal (X-axis) overflow on a DOM element.
51
+ * Reactively updates when the element is resized.
52
+ *
53
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
54
+ * @returns `isOverflowing` — whether the element overflows horizontally
55
+ * @returns `amount` — the number of overflowing pixels
56
+ * @returns `ratio` — `scrollWidth / clientWidth` (1 means no overflow)
57
+ * @returns `ref` — attach this to the element you want to observe
58
+ *
59
+ * @example
60
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowX();
61
+ * return <div ref={ref}>...</div>;
62
+ */
63
+ function n(e) {
64
+ return t((e) => ({
65
+ scrollSize: e.scrollWidth,
66
+ clientSize: e.clientWidth
67
+ }), e);
68
+ }
69
+ /**
70
+ * Detects vertical (Y-axis) overflow on a DOM element.
71
+ * Reactively updates when the element is resized.
72
+ *
73
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
74
+ * @returns `isOverflowing` — whether the element overflows vertically
75
+ * @returns `amount` — the number of overflowing pixels
76
+ * @returns `ratio` — `scrollHeight / clientHeight` (1 means no overflow)
77
+ * @returns `ref` — attach this to the element you want to observe
78
+ *
79
+ * @example
80
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowY();
81
+ * return <div ref={ref}>...</div>;
82
+ */
83
+ function r(e) {
84
+ return t((e) => ({
85
+ scrollSize: e.scrollHeight,
86
+ clientSize: e.clientHeight
87
+ }), e);
88
+ }
89
+ exports.useDetectOverflowX = n, exports.useDetectOverflowY = r;
@@ -0,0 +1,43 @@
1
+ import { RefObject } from "react";
2
+
3
+ //#region src/types.d.ts
4
+ type DetectOverflow<T> = {
5
+ isOverflowing: boolean;
6
+ amount: number;
7
+ ratio: number;
8
+ ref: RefObject<T | null>;
9
+ };
10
+ //#endregion
11
+ //#region src/index.d.ts
12
+ /**
13
+ * Detects horizontal (X-axis) overflow on a DOM element.
14
+ * Reactively updates when the element is resized.
15
+ *
16
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
17
+ * @returns `isOverflowing` — whether the element overflows horizontally
18
+ * @returns `amount` — the number of overflowing pixels
19
+ * @returns `ratio` — `scrollWidth / clientWidth` (1 means no overflow)
20
+ * @returns `ref` — attach this to the element you want to observe
21
+ *
22
+ * @example
23
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowX();
24
+ * return <div ref={ref}>...</div>;
25
+ */
26
+ declare function useDetectOverflowX<T extends HTMLElement>(externRef?: RefObject<T | null>): DetectOverflow<T>;
27
+ /**
28
+ * Detects vertical (Y-axis) overflow on a DOM element.
29
+ * Reactively updates when the element is resized.
30
+ *
31
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
32
+ * @returns `isOverflowing` — whether the element overflows vertically
33
+ * @returns `amount` — the number of overflowing pixels
34
+ * @returns `ratio` — `scrollHeight / clientHeight` (1 means no overflow)
35
+ * @returns `ref` — attach this to the element you want to observe
36
+ *
37
+ * @example
38
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowY();
39
+ * return <div ref={ref}>...</div>;
40
+ */
41
+ declare function useDetectOverflowY<T extends HTMLElement>(externRef?: RefObject<T | null>): DetectOverflow<T>;
42
+ //#endregion
43
+ export { useDetectOverflowX, useDetectOverflowY };
@@ -0,0 +1,43 @@
1
+ import { RefObject } from "react";
2
+
3
+ //#region src/types.d.ts
4
+ type DetectOverflow<T> = {
5
+ isOverflowing: boolean;
6
+ amount: number;
7
+ ratio: number;
8
+ ref: RefObject<T | null>;
9
+ };
10
+ //#endregion
11
+ //#region src/index.d.ts
12
+ /**
13
+ * Detects horizontal (X-axis) overflow on a DOM element.
14
+ * Reactively updates when the element is resized.
15
+ *
16
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
17
+ * @returns `isOverflowing` — whether the element overflows horizontally
18
+ * @returns `amount` — the number of overflowing pixels
19
+ * @returns `ratio` — `scrollWidth / clientWidth` (1 means no overflow)
20
+ * @returns `ref` — attach this to the element you want to observe
21
+ *
22
+ * @example
23
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowX();
24
+ * return <div ref={ref}>...</div>;
25
+ */
26
+ declare function useDetectOverflowX<T extends HTMLElement>(externRef?: RefObject<T | null>): DetectOverflow<T>;
27
+ /**
28
+ * Detects vertical (Y-axis) overflow on a DOM element.
29
+ * Reactively updates when the element is resized.
30
+ *
31
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
32
+ * @returns `isOverflowing` — whether the element overflows vertically
33
+ * @returns `amount` — the number of overflowing pixels
34
+ * @returns `ratio` — `scrollHeight / clientHeight` (1 means no overflow)
35
+ * @returns `ref` — attach this to the element you want to observe
36
+ *
37
+ * @example
38
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowY();
39
+ * return <div ref={ref}>...</div>;
40
+ */
41
+ declare function useDetectOverflowY<T extends HTMLElement>(externRef?: RefObject<T | null>): DetectOverflow<T>;
42
+ //#endregion
43
+ export { useDetectOverflowX, useDetectOverflowY };
package/dist/index.mjs ADDED
@@ -0,0 +1,89 @@
1
+ import { useCallback as e, useLayoutEffect as t, useRef as n, useState as r } from "react";
2
+ //#region src/overflow.tsx
3
+ /**
4
+ * Base hook for detecting overflow on a DOM element given axis.
5
+ * Observes the element for size changes and recomputes overflow reactively.
6
+ *
7
+ * @param getSizes - A function that extracts scroll and client sizes from the element
8
+ * @param externRef - An optional external ref to attach to the element. If not provided, an internal ref is created.
9
+ * @returns An object containing overflow state and the ref to attach to the element
10
+ *
11
+ * @example
12
+ * // Custom axis (e.g. both dimensions summed)
13
+ * const { isOverflowing, ref } = useDetectOverflow(
14
+ * (el) => ({ scrollSize: el.scrollWidth, clientSize: el.clientWidth }),
15
+ * );
16
+ */
17
+ function i(i, a) {
18
+ let o = n(null), s = n(i), c = a ?? o;
19
+ t(() => {
20
+ s.current = i;
21
+ }, [i]);
22
+ let [l, u] = r(!1), [d, f] = r(0), [p, m] = r(0), h = e((e) => {
23
+ let { scrollSize: t, clientSize: n } = s.current(e), r = t - n, i = n > 0 ? t / n : 0;
24
+ f(Math.max(0, r)), u(r > 0), m(i);
25
+ }, []);
26
+ return t(() => {
27
+ let e = c.current;
28
+ if (!e) {
29
+ console.warn(`ref is not attached to React element: ${e}`);
30
+ return;
31
+ }
32
+ h(e);
33
+ let t = new ResizeObserver((e) => {
34
+ e[0] && h(e[0].target);
35
+ });
36
+ return t.observe(e), () => {
37
+ t.unobserve(e);
38
+ };
39
+ }, [c, h]), {
40
+ isOverflowing: l,
41
+ amount: d,
42
+ ratio: p,
43
+ ref: c
44
+ };
45
+ }
46
+ //#endregion
47
+ //#region src/index.tsx
48
+ /**
49
+ * Detects horizontal (X-axis) overflow on a DOM element.
50
+ * Reactively updates when the element is resized.
51
+ *
52
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
53
+ * @returns `isOverflowing` — whether the element overflows horizontally
54
+ * @returns `amount` — the number of overflowing pixels
55
+ * @returns `ratio` — `scrollWidth / clientWidth` (1 means no overflow)
56
+ * @returns `ref` — attach this to the element you want to observe
57
+ *
58
+ * @example
59
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowX();
60
+ * return <div ref={ref}>...</div>;
61
+ */
62
+ function a(e) {
63
+ return i((e) => ({
64
+ scrollSize: e.scrollWidth,
65
+ clientSize: e.clientWidth
66
+ }), e);
67
+ }
68
+ /**
69
+ * Detects vertical (Y-axis) overflow on a DOM element.
70
+ * Reactively updates when the element is resized.
71
+ *
72
+ * @param externRef - An optional external ref. If not provided, an internal ref is created.
73
+ * @returns `isOverflowing` — whether the element overflows vertically
74
+ * @returns `amount` — the number of overflowing pixels
75
+ * @returns `ratio` — `scrollHeight / clientHeight` (1 means no overflow)
76
+ * @returns `ref` — attach this to the element you want to observe
77
+ *
78
+ * @example
79
+ * const { isOverflowing, amount, ratio, ref } = useDetectOverflowY();
80
+ * return <div ref={ref}>...</div>;
81
+ */
82
+ function o(e) {
83
+ return i((e) => ({
84
+ scrollSize: e.scrollHeight,
85
+ clientSize: e.clientHeight
86
+ }), e);
87
+ }
88
+ //#endregion
89
+ export { a as useDetectOverflowX, o as useDetectOverflowY };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "react-detect-overflow",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "./dist/index.d.mts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "scripts": {
22
+ "===================== build ======================": "",
23
+ "build": "tsdown",
24
+ "====================== npm =======================": "",
25
+ "package:test": "npm pack --dry-run",
26
+ "package": "npm pack",
27
+ "prepack": "npm run build",
28
+ "==================================================": ""
29
+ },
30
+ "files": [
31
+ "dist/*"
32
+ ],
33
+ "keywords": [
34
+ "react",
35
+ "hooks",
36
+ "overflow",
37
+ "detect",
38
+ "resize"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/Rainymy/react-detect-overflow.git"
43
+ },
44
+ "author": "Rainymy",
45
+ "license": "MIT",
46
+ "bugs": {
47
+ "url": "https://github.com/Rainymy/react-detect-overflow/issues"
48
+ },
49
+ "homepage": "https://github.com/Rainymy/react-detect-overflow#readme",
50
+ "peerDependencies": {
51
+ "react": ">=16.8.0"
52
+ },
53
+ "devDependencies": {
54
+ "@biomejs/biome": "^2.4.6",
55
+ "@types/react": "^19.2.14",
56
+ "publint": "^0.3.18",
57
+ "react": "^19.2.4",
58
+ "tsdown": "^0.21.1"
59
+ },
60
+ "sideEffects": false
61
+ }