- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- CalendarNew
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Date PickerNew
- Dialog
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
useMediaQuery
Reactive media query hook with Tailwind-like syntax.
A React hook that subscribes to a CSS media query and returns whether it matches. Built on useSyncExternalStore for SSR safety and concurrent mode compatibility.
Installation
pnpm dlx shadcn@latest add @coss/use-media-query
Usage
Breakpoint shorthand
Use Tailwind variant syntax to match breakpoints. TypeScript provides full autocomplete.
import { useMediaQuery } from "@/hooks/use-media-query";
// Min-width (breakpoint and above) — like md:
const isDesktop = useMediaQuery("md");
// Max-width (below breakpoint) — like max-md:
const isMobile = useMediaQuery("max-md");
// Range (between two breakpoints) — like md:max-lg:
const isTablet = useMediaQuery("md:max-lg");Object API
Use the object form when you need pointer detection or custom pixel values.
// Touch device detection
const isTouch = useMediaQuery({ pointer: "coarse" });
// Breakpoint + pointer combined
const isMobileTouch = useMediaQuery({ max: "md", pointer: "coarse" });
// Custom pixel values
const isNarrow = useMediaQuery({ max: 600 });Raw media query
Pass any valid CSS media query string as an escape hatch.
const prefersDark = useMediaQuery("(prefers-color-scheme: dark)");
const prefersReducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)");Conditional rendering
The primary use case — mount one component instead of another based on viewport.
function Layout() {
const isDesktop = useMediaQuery("lg");
return isDesktop ? <DesktopNav /> : <MobileNav />;
}Breakpoints
The hook includes a static breakpoint map that must match your Tailwind config. Default values:
| Name | Value |
|---|---|
sm | 640px |
md | 800px |
lg | 1024px |
xl | 1280px |
2xl | 1536px |
3xl | 1600px |
4xl | 2000px |
If you override breakpoints in your Tailwind CSS @theme, update the BREAKPOINTS constant in the hook to match.
API
function useMediaQuery(
query: BreakpointQuery | MediaQueryInput | string
): boolean;String queries
| Pattern | Example | Matches |
|---|---|---|
"{bp}" | "md" | Viewport ≥ breakpoint |
"max-{bp}" | "max-md" | Viewport < breakpoint |
"{bp}:max-{bp}" | "md:max-lg" | Between two breakpoints |
"(...)" | "(prefers-color-scheme: dark)" | Raw CSS media query |
Object queries
| Property | Type | Description |
|---|---|---|
min | Breakpoint | number | Min-width breakpoint name or px value |
max | Breakpoint | number | Max-width breakpoint name or px value |
pointer | "coarse" | "fine" | Pointer type (coarse for touch, fine for mouse) |
Return value
Returns boolean — true when the media query matches, false otherwise. Returns false during SSR.
Examples
Resize the viewport to see values update in real time.
Min-width (breakpoint and above)
useMediaQuery("sm")≥ 640pxfalseuseMediaQuery("md")≥ 800pxfalseuseMediaQuery("lg")≥ 1024pxfalseuseMediaQuery("xl")≥ 1280pxfalseuseMediaQuery("2xl")≥ 1536pxfalse
Max-width (below breakpoint)
useMediaQuery("max-sm")< 640pxfalseuseMediaQuery("max-md")< 800pxfalseuseMediaQuery("max-lg")< 1024pxfalse
Ranges
useMediaQuery("sm:max-md")640 - 799pxfalseuseMediaQuery("md:max-lg")800 - 1023pxfalseuseMediaQuery("lg:max-xl")1024 - 1279pxfalse
Device & preferences
useMediaQuery({ pointer: "coarse" })touchfalseuseMediaQuery({ pointer: "fine" })mousefalseuseMediaQuery("(prefers-color-scheme: dark)")falseuseMediaQuery("(prefers-reduced-motion: reduce)")false
Convenience export
The hook also exports useIsMobile for backward compatibility with shadcn's use-mobile pattern:
import { useIsMobile } from "@/hooks/use-media-query";
const isMobile = useIsMobile(); // equivalent to useMediaQuery("max-md")