Logo
Published on

The Best Way to Detect Mobile Devices in Next.js 14

Authors

Recently I decided to create an e-commerce application from scratch with NextJS. As you all know in such a complex application it is sometimes necessary to know if the user is using a mobile or desktop device. I searched for information to know how to implement this functionality in NextJS and when I applied it in my application I realized that it was very slow and the products of the store were loaded before (thanks to the server actions) than the simple functionality of checking if it is mobile or not. As I am obsessed with my applications being super optimized I started to investigate another way to check it using NextJS server actions. It is clear that I have found the way and I am going to show it to you in this article along with the best way to get the screen width in client components:

I'm looking for part-time work! check out my portfolioand contact me.

Detecting Mobile Devices in Server Components

To implement this functionality we will need to install this library:

npm install ua-parser-js @types/ua-parser-js

This tool not only allows us to detect the device, but also allows us to detect the browser, the engine, the OS, and the CPU. You can see more information about this library here.

It is a very useful tool that will undoubtedly help you to create your applications.

To detect the device we simply have to follow the steps below:

srclibs

'use server'

import { headers } from 'next/headers'
import { UAParser } from 'ua-parser-js'

export const isMobileDevice = () => {
  if (typeof process === 'undefined') {
    throw new Error('[Server method] you are importing a server-only module outside of server')
  }

  const { get } = headers()
  const ua = get('user-agent')

  const device = new UAParser(ua || '').getDevice()

  return device.type === 'mobile'
}

Personally, I have decided to have the file in the libs folder but you can obviously have it wherever you want.

To use this functionality in your application you need to import and execute this function in a Server Component, for example if you want to use it in the Header of your application you can import it in the layout file and pass it as props to this component as I do in this example:

srcapplayout.tsx

import type { Metadata } from "next";
import { Header } from "@/components/common/Header";
import { Inter } from "next/font/google";
import { isMobileDevice } from "@/libs/responsive"; // import the function

import './globals.css'

export const metadata: Metadata = {
  title: "Test APP",
  description: "This is a test APP",
};

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const mobile = isMobileDevice(); // execute the function

return (

{' '}

<html className="scroll-smooth" lang="en">
  <body className={inter.className}>
    <main className="min-h-screen">
      <Header
        isMobile={mobile} // pass it as props to the client component
      />
      {children}
    </main>
  </body>
</html>
); }

Detecting Mobile Devices in Client Components

To use this functionality in client components no library is needed but we must take into account several things: being a custom hook can only be used in client components and does not detect the type of device but the width of the screen, this can give us more flexibility when creating our application but may have certain limitations such as loading time.

srchooksuseClientMediaQuery.js

'use client'

import { useEffect, useState } from 'react'

export function useClientMediaQuery(query) {
  const [matches, setMatches] = useState(null)

  useEffect(() => {
    const mediaQueryList = window.matchMedia(query)

    const handleMatchChange = (e) => {
      setMatches(e.matches)
    }

    mediaQueryList.addEventListener('change', handleMatchChange)
    setMatches(mediaQueryList.matches)

    return () => {
      mediaQueryList.removeEventListener('change', handleMatchChange)
    }
  }, [query])

  return matches
}

To use this hook in your application you only have to import it, execute the function, and pass as a parameter the pixels with which you are going to consider that it is mobile, this function not only can be used to detect if it is mobile but also to detect different widths of the screen.

'use client'

import { useClientMediaQuery } from '@/hooks/useClientMediaQuery'

const isMobile = useClientMediaQuery('(max-width: 600px)')