React Hooks
Responsive design utilities for AbsoluteJS React applications. SSR-aware viewport breakpoints with user-agent detection for zero-layout-shift server rendering.
#useMediaQuery
The useMediaQuery hook provides viewport-based responsive breakpoints. It returns the current breakpoint name and two helper functions for checking size ranges.
xs, sm, md, lg, xl, 2xl)true if the viewport is at or above the given breakpointtrue if the viewport is at or below the given breakpointimport { useMediaQuery } from '@absolutejs/absolute/react/hooks';
export const ResponsiveLayout = () => {
const { breakpoint, isSizeOrGreater, isSizeOrLess } = useMediaQuery();
return (
<div>
<p>Current breakpoint: {breakpoint}</p>
{isSizeOrGreater('lg') && (
<aside>Desktop sidebar: only visible on lg and above</aside>
)}
{isSizeOrLess('sm') && (
<nav>Mobile bottom nav: only visible on sm and below</nav>
)}
</div>
);
};#UserAgentProvider
The UserAgentProvider is an SSR-aware context provider that passes the user-agent string to useMediaQuery. On the server, the hook reads the user-agent to infer whether the client is mobile or desktop and returns a sensible default breakpoint. On the client, it switches to real viewport measurement via matchMedia.
// In your page component or layout
import { UserAgentProvider } from '@absolutejs/absolute/react/hooks';
export const App = ({ userAgent, children }: {
userAgent: string;
children: React.ReactNode;
}) => (
<UserAgentProvider userAgent={userAgent}>
{children}
</UserAgentProvider>
);
// AbsoluteJS page handlers pass the user-agent automatically:
import { reactHandler } from '@absolutejs/absolute';
app.get('/', reactHandler({
component: 'HomePage',
head: { title: 'Home' },
props: async ({ request }) => {
return { userAgent: request.headers.get('user-agent') ?? '' };
}
}));#Breakpoints
The default breakpoints match Tailwind CSS values. The hook checks viewport width against these thresholds and returns the largest breakpoint that the current width satisfies.
// Default breakpoints (matches Tailwind CSS)
// xs: 0px
// sm: 640px
// md: 768px
// lg: 1024px
// xl: 1280px
// 2xl: 1536px
// The hook returns the current breakpoint name based on
// viewport width. On the server, it infers a reasonable
// default from the user-agent string (mobile vs desktop).
import { useMediaQuery } from '@absolutejs/absolute/react/hooks';
export const AdaptiveGrid = () => {
const { breakpoint, isSizeOrGreater } = useMediaQuery();
const columns = isSizeOrGreater('xl') ? 4
: isSizeOrGreater('lg') ? 3
: isSizeOrGreater('md') ? 2
: 1;
return (
<div style={{
display: 'grid',
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: '1rem'
}}>
{/* grid items */}
</div>
);
};#SSR Usage
When rendering on the server, there is no window object to measure. The UserAgentProvider solves this by parsing the user-agent string to detect mobile devices. Mobile user-agents get sm as the default breakpoint, and desktop user-agents get lg. This means the server renders the correct layout variant on the first pass, avoiding layout shift when the client hydrates.
// SSR-aware responsive rendering
// On the server, useMediaQuery reads the user-agent to detect
// mobile vs desktop and returns a sensible default breakpoint.
// On the client, it switches to real viewport measurement.
import { useMediaQuery } from '@absolutejs/absolute/react/hooks';
import { UserAgentProvider } from '@absolutejs/absolute/react/hooks';
export const Page = ({ userAgent }: { userAgent: string }) => (
<UserAgentProvider userAgent={userAgent}>
<Layout />
</UserAgentProvider>
);
const Layout = () => {
const { isSizeOrGreater, isSizeOrLess } = useMediaQuery();
return (
<div>
{/* Server renders the correct variant: no layout shift */}
{isSizeOrGreater('md') ? (
<DesktopNav />
) : (
<MobileNav />
)}
<main>
{isSizeOrLess('sm') && <MobileBanner />}
<Content />
</main>
</div>
);
};#API Reference
// useMediaQuery return type
type UseMediaQueryResult = {
// Current breakpoint name: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
breakpoint: string;
// Returns true if the viewport is at or above the given breakpoint
isSizeOrGreater: (size: Breakpoint) => boolean;
// Returns true if the viewport is at or below the given breakpoint
isSizeOrLess: (size: Breakpoint) => boolean;
};
type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
// Default breakpoint values
const defaultBreakpoints: Record<Breakpoint, number> = {
'xs': 0,
'sm': 640,
'md': 768,
'lg': 1024,
'xl': 1280,
'2xl': 1536
};