react-adaptive-render
v1.0.2
Published
Device-aware adaptive UI rendering for React and Next.js — SSR safe, lazy loading, tree-shakable
Maintainers
Readme
react-adaptive-render
Device-aware adaptive UI rendering for React & Next.js.
SSR safe · Lazy loading · Tree-shakable · TypeScript · ~2KB
Why
CSS media queries style the same component differently. This library renders completely different components per device — while lazy-loading only the one that's needed.
| Feature | CSS media queries | react-adaptive-render | |---|---|---| | Responsive styles | yes | yes | | Different component trees | no | yes | | Lazy / code-split loading | no | yes | | SSR device hint (no flash) | no | yes | | Custom breakpoints | no | yes |
Install
npm install react-adaptive-render
# or
yarn add react-adaptive-renderQuick Start
1. <Adaptive> — render different JSX per device
import { Adaptive } from "react-adaptive-render"
export function Navbar() {
return (
<Adaptive
mobile={<MobileNavbar />}
tablet={<TabletNavbar />}
desktop={<DesktopNavbar />}
/>
)
}Missing variants fall back gracefully: tablet → desktop, mobile → tablet → desktop.
2. adaptiveDynamic — lazy load separate bundles per device
import { adaptiveDynamic } from "react-adaptive-render"
const Layout = adaptiveDynamic({
mobile: () => import("./mobile/Layout"),
tablet: () => import("./tablet/Layout"),
desktop: () => import("./desktop/Layout"),
})
export default function Page() {
return <Layout />
}Only the matching bundle is downloaded. Mobile users never download desktop code.
3. useDevice — simple hook
import { useDevice } from "react-adaptive-render"
function Sidebar() {
const device = useDevice()
// "mobile" | "tablet" | "desktop"
if (device === "mobile") return <Drawer />
return <Sidebar />
}4. useAdaptive — full device info
import { useAdaptive } from "react-adaptive-render"
function Banner() {
const { isMobile, orientation, width } = useAdaptive()
return (
<div>
{isMobile && orientation === "portrait" ? "Portrait mobile" : "Other"}
— width: {width}px
</div>
)
}5. useBreakpoint — arbitrary min/max check
import { useBreakpoint } from "react-adaptive-render"
const isWide = useBreakpoint({ minWidth: 1200 })
const isSmall = useBreakpoint({ maxWidth: 480 })Next.js SSR Setup (prevents hydration flash)
In app/layout.tsx (App Router):
import { headers } from "next/headers"
import { AdaptiveProvider, detectDeviceSSR } from "react-adaptive-render"
export default function RootLayout({ children }) {
const ua = headers().get("user-agent") ?? ""
const ssrDevice = detectDeviceSSR(ua)
return (
<html>
<body>
<AdaptiveProvider ssrDevice={ssrDevice}>
{children}
</AdaptiveProvider>
</body>
</html>
)
}Custom Breakpoints
<AdaptiveProvider
breakpoints={{
mobile: 640, // ≤ 640px → mobile
tablet: 1024, // ≤ 1024px → tablet
// > 1024px → desktop
}}
>
{children}
</AdaptiveProvider>API Reference
Components
| Name | Props | Description |
|---|---|---|
| <Adaptive> | mobile? tablet? desktop? fallback? | Renders matching ReactNode |
| <AdaptiveProvider> | breakpoints? ssrDevice? | Global config provider |
Functions
| Name | Signature | Description |
|---|---|---|
| adaptiveDynamic | (loaders, fallback?) => Component | Lazy device-split component |
| detectDeviceSSR | (userAgent: string) => DeviceType | SSR user-agent detection |
Hooks
| Name | Returns | Description |
|---|---|---|
| useDevice() | DeviceType | Current device string |
| useAdaptive() | DeviceInfo | Full device info object |
| useBreakpoint(opts) | boolean | Matches min/max width range |
TypeScript
All types are exported:
import type {
DeviceType, // "mobile" | "tablet" | "desktop"
Orientation, // "portrait" | "landscape"
Breakpoints, // { mobile: number; tablet: number }
DeviceInfo, // full useAdaptive() return type
AdaptiveProps,
} from "react-adaptive-render"License
MIT
