react-media
@opensea/react-media
is a Javascript library to deal with media queries in isomorphic React applications.
Its heavily inspired by https://github.com/artsy/fresnel but is compatible with React 18.
Installation
npm
npm i @opensea/react-media
yarn
yarn add @opensea/react-media
Usage
import { createMedia } from "@opensea/react-media"
const { createMediaStyle, prepareComponents } = createMedia({
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
"2xl": 1536,
container: 1600,
"3xl": 1910,
})
export const mediaStyle = createMediaStyle()
import { prepareComponents } from "./setup"
const { Media, SizeProvider, useSizeContextSelector } = prepareComponents()
export { Media, SizeProvider, useSizeContextSelector }
import { Media } from "./media/components"
export function ComponentX() {
return <Media greaterThan="md">Render if greater than md</Media>
}
NextJS ~ Pages router
import React from "react"
import { SizeProvider } from "./media/components"
import type { AppProps } from "next/app"
export default function App({ Component, pageProps }: AppProps) {
return (
<SizeProvider>
<Component {...pageProps} />
</SizeProvider>
)
}
import { Html, Head, Main, NextScript } from "next/document"
import { mediaStyles } from "./media/setup"
export default function Document() {
return (
<Html>
<Head>
<style
dangerouslySetInnerHTML={{ __html: mediaStyles }}
type="text/css"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
NextJS ~ App router / RSC
"use client"
import { SizeProvider } from "./media/components"
export function ClientProviders(props: { children: React.ReactNode }) {
return <SizeProvider>{props.children}</SizeProvider>
}
import { ClientProviders } from "./client-providers"
import { mediaStyles } from "./media/setup"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<style
dangerouslySetInnerHTML={{ __html: mediaStyles }}
type="text/css"
/>
</head>
<body>
<ClientProviders>{children}</ClientProviders>
</body>
</html>
)
}
Using breakpoints in javascript code
Note: useSizeContextSelector
hook relies on the window width/height which is not accessible on the server.
As such its not suitable for rendering content based on it as it will lead to server-client miss-matches.
import { breakpoints } from "./media/setup"
import { useSizeContextSelector } from "./media/components"
const useIsLessThanLg = () => {
return useSizeContextSelector(value => value.width < breakpoints.lg)
}
export function ComponentX() {
const isLessThanLg = useIsLessThanLg()
return (
<button
onClick={() => {
if (isLessThanLg) {
console.log("less than lg")
} else {
console.log("not less than lg")
}
}}
>
Click me
</button>
)
}