diff --git a/packages/@mantine/hooks/src/use-resize-observer/UseResizeObserver.story.tsx b/packages/@mantine/hooks/src/use-resize-observer/UseResizeObserver.story.tsx
new file mode 100644
index 0000000000..f90218c861
--- /dev/null
+++ b/packages/@mantine/hooks/src/use-resize-observer/UseResizeObserver.story.tsx
@@ -0,0 +1,66 @@
+import { useResizeObserver } from './use-resize-observer';
+
+export default { title: 'use-resize-observer' };
+
+export function Usage() {
+ const [ref, rect] = useResizeObserver();
+ return (
+
+
+
+ 1
+
+
+ 2
+
+
+ 3
+
+
+ 4
+
+
+
+
Width: {rect?.width}
+
Height: {rect?.height}
+
+
+ );
+}
diff --git a/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.test.tsx b/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.test.tsx
new file mode 100644
index 0000000000..cf8a0d36ff
--- /dev/null
+++ b/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.test.tsx
@@ -0,0 +1,92 @@
+import { renderHook } from '@testing-library/react';
+import { useElementSize, useResizeObserver } from './use-resize-observer';
+
+class MockResizeObserver {
+ observe = jest.fn();
+ disconnect = jest.fn();
+}
+
+let mockObserverInstance: MockResizeObserver;
+
+const originalResizeObserver = global.ResizeObserver;
+const originalRAF = window.requestAnimationFrame;
+const originalCAF = window.cancelAnimationFrame;
+
+describe('@mantine/hooks/use-resize-observer', () => {
+ beforeEach(() => {
+ global.ResizeObserver = jest.fn().mockImplementation(() => {
+ mockObserverInstance = new MockResizeObserver();
+ return mockObserverInstance;
+ }) as any;
+
+ window.requestAnimationFrame = (callback) => window.setTimeout(callback, 0) as any;
+ window.cancelAnimationFrame = jest.fn();
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ afterAll(() => {
+ global.ResizeObserver = originalResizeObserver;
+ window.requestAnimationFrame = originalRAF;
+ window.cancelAnimationFrame = originalCAF;
+ });
+
+ it('returns reference and default dimensions', () => {
+ const { result } = renderHook(() => useResizeObserver());
+ const [ref, rect] = result.current;
+
+ expect(ref.current).toBe(null);
+ expect(rect).toEqual({
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ top: 0,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ });
+ });
+
+ it('calls observe on mount and disconnect on unmount', () => {
+ const { unmount } = renderHook(() => useResizeObserver());
+
+ expect(global.ResizeObserver).toHaveBeenCalled();
+
+ unmount();
+
+ expect(mockObserverInstance.disconnect).toHaveBeenCalled();
+ });
+});
+
+describe('@mantine/hooks/use-element-size', () => {
+ beforeEach(() => {
+ global.ResizeObserver = jest.fn().mockImplementation(() => {
+ mockObserverInstance = new MockResizeObserver();
+ return mockObserverInstance;
+ }) as any;
+
+ window.requestAnimationFrame = (callback) => window.setTimeout(callback, 0);
+ window.cancelAnimationFrame = jest.fn();
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ afterAll(() => {
+ global.ResizeObserver = originalResizeObserver;
+ window.requestAnimationFrame = originalRAF;
+ window.cancelAnimationFrame = originalCAF;
+ });
+
+ it('returns reference and default dimensions', () => {
+ const { result } = renderHook(() => useElementSize());
+
+ expect(result.current.ref.current).toBe(null);
+ expect(result.current.width).toBe(0);
+ expect(result.current.height).toBe(0);
+ });
+});
diff --git a/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts b/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts
index 236fc3d4c1..017998c7fa 100644
--- a/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts
+++ b/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts
@@ -30,7 +30,24 @@ export function useResizeObserver(options?: ResizeO
frameID.current = requestAnimationFrame(() => {
if (ref.current) {
- setRect(entry.contentRect);
+ const boxSize = entry.borderBoxSize?.[0] || entry.contentBoxSize?.[0];
+ if (boxSize) {
+ const width = boxSize.inlineSize;
+ const height = boxSize.blockSize;
+
+ setRect({
+ width,
+ height,
+ x: entry.contentRect.x,
+ y: entry.contentRect.y,
+ top: entry.contentRect.top,
+ left: entry.contentRect.left,
+ bottom: entry.contentRect.bottom,
+ right: entry.contentRect.right,
+ });
+ } else {
+ setRect(entry.contentRect);
+ }
}
});
}