useWindowSize
A React hook that tracks the window dimensions.
Installation
npx shadcn@latest add https://r.fiberui.com/r/hooks/use-window-size.jsonFeatures
- Responsive Updates - Updates width and height on window resize.
- Debounced - Can be easily debounced (see example).
- SSR Safe - Returns
0or initial values during server-side rendering to match hydration.
Source Code
View the full hook implementation in the Hook Source Code section below.
Interactive Example
Window Dimensions
Resize your browser window to see updates.
Width0px
Height0px
Current Viewport: Mobile (< 768px)
"use client";
import { useWindowSize } from "@repo/hooks/dom/use-window-size";
import { Maximize2 } from "lucide-react";
export const Example1 = () => {
const { width, height } = useWindowSize();
const isMobile = width < 768;
return (
<div className="flex w-full max-w-md flex-col gap-4">
<div className="flex items-center gap-2">
<Maximize2 className="text-primary h-5 w-5" />
<h3 className="font-semibold">Window Dimensions</h3>
</div>
<p className="text-muted-foreground text-sm">
Resize your browser window to see updates.
</p>
<div className="bg-muted/50 grid grid-cols-2 gap-px overflow-hidden rounded-lg border">
<div className="bg-background flex flex-col items-center justify-center p-6">
<span className="text-muted-foreground mb-1 text-xs uppercase tracking-wider">
Width
</span>
<span className="text-primary font-mono text-3xl font-bold">
{width}
</span>
<span className="text-muted-foreground text-xs">px</span>
</div>
<div className="bg-background flex flex-col items-center justify-center p-6">
<span className="text-muted-foreground mb-1 text-xs uppercase tracking-wider">
Height
</span>
<span className="text-primary font-mono text-3xl font-bold">
{height}
</span>
<span className="text-muted-foreground text-xs">px</span>
</div>
</div>
<div
className={`rounded-md px-3 py-2 text-center text-sm font-medium transition-colors ${
isMobile
? "bg-blue-500/10 text-blue-600"
: "bg-green-500/10 text-green-600"
}`}
>
Current Viewport: {isMobile ? "Mobile" : "Desktop"} (
{width < 768 ? "<" : "ā„"} 768px)
</div>
</div>
);
};
const { width, height } = useWindowSize();
const isMobile = width < 768;Responsive Layout
Renders different components based on window width.
Responsive Component Switching
mobile Layout
0px768px1024pxā
MobileTabletDesktop
Resize the window to switch the rendered icon and layout logic.
"use client";
import { useWindowSize } from "@repo/hooks/dom/use-window-size";
import { Laptop, Smartphone, Tablet } from "lucide-react";
export const Example2 = () => {
const { width } = useWindowSize();
let deviceType = "desktop";
let Icon = Laptop;
let color = "text-blue-500";
if (width < 768) {
deviceType = "mobile";
Icon = Smartphone;
color = "text-green-500";
} else if (width < 1024) {
deviceType = "tablet";
Icon = Tablet;
color = "text-orange-500";
}
return (
<div className="flex w-full max-w-md flex-col items-center gap-6">
<h3 className="font-semibold">Responsive Component Switching</h3>
<div className="flex flex-col items-center gap-2">
<Icon
className={`h-16 w-16 ${color} transition-all duration-300`}
/>
<p className="font-medium capitalize">{deviceType} Layout</p>
</div>
<div className="w-full space-y-2">
<div className="text-muted-foreground flex justify-between text-xs">
<span>0px</span>
<span>768px</span>
<span>1024px</span>
<span>ā</span>
</div>
<div className="bg-muted h-2 w-full overflow-hidden rounded-full">
<div
className="bg-primary h-full transition-all duration-300"
style={{
width: `${Math.min((width / 1200) * 100, 100)}%`,
}}
/>
</div>
<div className="flex justify-between font-mono text-xs">
<span
className={
width < 768
? "font-bold text-green-600"
: "text-muted-foreground"
}
>
Mobile
</span>
<span
className={
width >= 768 && width < 1024
? "font-bold text-orange-600"
: "text-muted-foreground"
}
>
Tablet
</span>
<span
className={
width >= 1024
? "font-bold text-blue-600"
: "text-muted-foreground"
}
>
Desktop
</span>
</div>
</div>
<p className="text-muted-foreground text-center text-sm">
Resize the window to switch the rendered icon and layout logic.
</p>
</div>
);
};
const { width } = useWindowSize();
if (width < 768) return <MobileLayout />;
return <DesktopLayout />;API Reference
Signature
const { width, height } = useWindowSize();Returns
| Property | Type | Description |
|---|---|---|
width | number | Window width in pixels. |
height | number | Window height in pixels. |
Hook Source Code
import { useState, useCallback } from "react";
import { useEventListener } from "@repo/hooks/dom/use-event-listener";
interface WindowSize {
width: number;
height: number;
}
const isBrowser = typeof window !== "undefined";
/**
* useWindowSize - Track window dimensions
*
* @returns Object with width and height of the window
*
* @example
* const { width, height } = useWindowSize();
*/
export function useWindowSize(): WindowSize {
const [size, setSize] = useState<WindowSize>(() => ({
width: isBrowser ? window.innerWidth : 0,
height: isBrowser ? window.innerHeight : 0,
}));
const handleResize = useCallback(() => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
}, []);
useEventListener("resize", handleResize);
return size;
}