The useIsMobile hook provides a simple way to detect whether the current viewport is mobile-sized (width < 640px), with automatic updates when the window is resized.
Signature
function useIsMobile () : boolean
Returns
true if the viewport width is less than 640px, false otherwise
Implementation
import { useState , useEffect } from 'react'
export const useIsMobile = () : boolean => {
const [ isMobile , setIsMobile ] = useState < boolean >( false )
useEffect (() => {
const check = () => setIsMobile ( window . innerWidth < 640 )
check ()
window . addEventListener ( 'resize' , check )
return () => window . removeEventListener ( 'resize' , check )
}, [])
return isMobile
}
How it works
Initial state : Starts with false to prevent hydration mismatches
Effect runs : After mount, checks the current window width
Event listener : Attaches resize listener for responsive updates
Cleanup : Removes listener on unmount to prevent memory leaks
The initial state is false to match the server-rendered state. The actual check happens client-side after hydration.
Usage
Basic responsive behavior
import { useIsMobile } from '@/hooks'
function ResponsiveComponent () {
const isMobile = useIsMobile ()
return (
< div >
{ isMobile ? (
< MobileView />
) : (
< DesktopView />
)}
</ div >
)
}
Conditional rendering
import { useIsMobile } from '@/hooks'
function Navigation () {
const isMobile = useIsMobile ()
return (
< nav >
{ isMobile ? (
< HamburgerMenu />
) : (
< FullNavigation />
)}
</ nav >
)
}
Adjust layout based on screen size
import { useIsMobile } from '@/hooks'
function Gallery () {
const isMobile = useIsMobile ()
const columns = isMobile ? 2 : 4
const imageSize = isMobile ? 'small' : 'large'
return (
< div className = { `grid grid-cols- ${ columns } ` } >
{ items . map ( item => (
< Image key = {item. id } size = { imageSize } />
))}
</ div >
)
}
Breakpoint
The hook uses 640px as the mobile breakpoint, which corresponds to Tailwind CSS’s sm breakpoint.
Breakpoint Width Classification < 640px Mobile isMobile = true≥ 640px Desktop isMobile = false
If you need custom breakpoints, consider creating a variant like useBreakpoint(width) or use CSS media queries with Tailwind’s responsive classes.
Debouncing resize events
For performance-critical applications, consider debouncing the resize handler:
import { useIsMobile } from '@/hooks'
import { useDebounce } from '@/hooks'
function PerformantComponent () {
const isMobileRaw = useIsMobile ()
const isMobile = useDebounce ( isMobileRaw , 150 )
// Now resize events are debounced by 150ms
return < div >{isMobile ? 'Mobile' : 'Desktop' } </ div >
}
SSR considerations
The hook initializes to false on the server to avoid hydration mismatches. The actual value is computed client-side after mount.
function SafeComponent () {
const isMobile = useIsMobile ()
const [ hydrated , setHydrated ] = useState ( false )
useEffect (() => setHydrated ( true ), [])
if ( ! hydrated ) {
return < Skeleton />
}
return isMobile ? < MobileView /> : < DesktopView />
}
useDebounce Debounce rapidly changing values
useHydrated Detect client-side hydration completion