Technical Guide : Setup NextJS with Leaflet

Getting Started Jan 04, 2024

Setup NextJS

you can create next js with create-next-js-app

npx create-next-app nextjs-leaflet
# or
yarn create next-app nextjs-leaflet

or use template like starter nextjs tailwindcss

npx degit sozonome/nextarter-tailwind nextjs-leaflet
cd nextjs-leaflet

Setup Leaflet

Because leaflet its not reactjs, we need dependencies for reactjs with react-leaflet. Docs about react-leaflet can read here

yarn add leaflet react-leaflet

if you're using typescript, its react-leaflet support typescript too.

yarn add -D @types/leaflet

Create Map Components

Take a Note, my components look like this:

First, we create Map Components in src/lib/components

import L from 'leaflet';
import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';

const Maps = () => {
  const icon = L.icon({ iconUrl: '/images/marker-icon.png' });

  return (
    <div className="w-full">
        className="h-[300px] w-full"
        center={[51.505, -0.09]}
          attribution='&copy; <a href="">OpenStreetMap</a> contributors'
        <Marker position={[51.505, -0.09]} icon={icon}>
            A pretty CSS3 popup. <br /> Easily customizable.

export default Maps;

Explain :

Import Statements:

  • import L from 'leaflet';: This line imports the Leaflet library, a JavaScript library for interactive maps. L is a conventional shorthand used to refer to Leaflet.
  • import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';: This line imports specific components from the react-leaflet package. These components are React-friendly wrappers for corresponding Leaflet functionalities.

Component Definition - Maps:

  • const Maps = () => { ... };: This line defines a functional component named Maps in React.

Leaflet Icon Configuration:

  • const icon = L.icon({ iconUrl: '/images/marker-icon.png' });: This creates a custom icon for map markers using Leaflet's icon method. The icon image is loaded from the specified URL (/images/marker-icon.png).
  • The issue arises due to the malfunctioning of the default icons provided by react-leaflet, necessitating the creation of custom icons.

Rendering the Map:

  • <div className="w-full">...</div>: The map is wrapped inside a div element with a full width. This div acts as a container for the map.
  • <MapContainer className="h-[300px] w-full" center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}>... </MapContainer>: This is the root component for the map. It uses the following props:
  • className="h-[300px] w-full": Sets the height and width of the map.
  • center={[51.505, -0.09]}: Sets the initial geographical center of the map (latitude and longitude).
  • zoom={13}: Sets the initial zoom level of the map.
  • scrollWheelZoom={false}: Disables zooming in/out using the mouse scroll wheel.

Tile Layer Configuration:

  • <TileLayer ... />: This component is used to display the map tiles (the visual imagery of the map).
  • attribution='...': Provides attribution text for the map tiles, which is a requirement for many free tile providers like OpenStreetMap.
  • url="https://{s}{z}/{x}/{y}.png": Specifies the URL template for loading map tiles. {s}, {z}, {x}, and {y} are placeholders that Leaflet replaces with actual values when making requests for tiles.

Marker Configuration:

  • <Marker position={[51.505, -0.09]} icon={icon}> ... </Marker>: Places a marker on the map.
  • position={[51.505, -0.09]}: Sets the geographical coordinates where the marker is placed.
  • icon={icon}: Applies the custom icon created earlier to this marker.

Popup Configuration:

  • <Popup> ... </Popup>: Defines a popup that appears when you click on the marker.
  • The content inside the <Popup> tags (A pretty CSS3 popup. <br /> Easily customizable.) is the text displayed in the popup.

Export Statement:

  • export default Maps;: This line exports the Maps component, making it available for import and use in other parts of the application.

Overall, this Maps component renders an interactive map centered at a specific geographical point, with a single marker using a custom icon. When clicked, this marker shows a customizable popup with text.

Second, we import css from leaflet in layout.tsx

import 'leaflet/dist/leaflet.css';
import '@/lib/styles/globals.css';


This ensures that the necessary CSS for creating a Leaflet map is present, allowing for the proper display and functionality of the map.

Third, we call Maps components and show it home components

'use client';

import type { NextPage } from 'next';
import dynamic from 'next/dynamic';

import SomeText from '@/lib/components/samples/SomeText';

const Home: NextPage = () => {
  const NotSSRMaps = dynamic(() => import('@/lib/components/maps'), {
    ssr: false,

  return (
    <div className="mx-auto flex min-h-[60vh] w-full max-w-screen-lg flex-col items-center justify-center gap-8 text-center">
      <SomeText />
      <NotSSRMaps />

export default Home;

Client-Side Only Directive:

  • 'use client';: This is a directive indicating that the code should only run on the client-side. It's specific to Next.js 12 and later versions, allowing you to specify per-module whether the code is intended for the server, client, or both.

Dynamic Import of NotSSRMaps Component:

  • const NotSSRMaps = dynamic(() => import('@/lib/components/maps'), { ssr: false });: Here, the dynamic function is used to import the maps component (@/lib/components/maps) dynamically. The option { ssr: false } indicates that this component should not be rendered on the server during server-side rendering. This is often necessary for components that rely on window or other browser-specific APIs, which are not available during SSR.

If everything is correct, it should display something like this:

Full Code:

nextjs-leaflet/src/lib/pages/home/index.tsx at main ยท naufaldi/nextjs-leaflet
Setup NextJS with leaflet. Contribute to naufaldi/nextjs-leaflet development by creating an account on GitHub.



Manusia pada umumnya

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.