Nuxt 3 Google Maps Component

Nuxt 3 Google Maps Component

·

7 min read

You can do a lot of things with Google Maps right? In this short tutorial, we will create a Google Maps component with Nuxt3. We will also add tailwind and tailwind elements to our projects.

In the end, we want to have a component that looks like this:

Adding tailwind and tailwind elements

Tailwind.css is a pretty popular and great CSS framework. That's why we are going to use it in this project. We also want to have some components built with tailwind so we don't have to create them on our own. That's why we use tailwind elements.

Adding tailwind

Once you created your Nuxt 3 project you can add the Nuxt tailwind module dependency to it. It's very easy and fast to do that. We are using ǹpm and just run:

npm install --save-dev @nuxtjs/tailwindcss

After that, we only need to add the module to our nuxt.config.ts

export default defineNuxtConfig({
    modules: ['@nuxtjs/tailwindcss']
})

That's it now we are ready to use tailwind in our project. We only need to add the classes to our components.

Adding tailwind elements

Tailwind elements will give us a bunch of components. We are going to use the accordion component for the Google Maps we are building. Let's install it with:

npm install tw-elements

After installing tailwind elements we also need to adjust our tailwind.config.js :

const plugin = require('tailwindcss/plugin');

module.exports = {
    content: [
        './src/**/*.{html,js}', 
        './node_modules/tw-elements/dist/js/**/*.js'
    ],
    plugins: [
      require('tw-elements/dist/plugin')
    ]
};

Now we have our tailwind dependencies installed. Let's install Google Maps next.

Google Maps

We are using Vue 3 Google Map. This works with Nuxt 3 and works pretty well. Install it with:

npm i vue3-google-map

We are all set up now and can use Google Maps already. Let's create our Nuxt 3 Google Map component that reacts on an accordion.

Nuxt 3 Components

For the final result we need 3 components:

  • Accordion

  • MarkerList / MarkerCluster

  • Google Map

In our accordion, we put information from popular soccer clubs from the 1. Bundesliga. I don't know anything about soccer so there will just be some random text.

Our MarkerList will handle the locations on Google Maps. We want to add custom markers to the locations of the clubs' stadiums.

And in our Map, we put the components together and render a Google Map.

Tailwind Elements - Accordion

Since we are using tailwind elements we simply can use the Accordion Component from there.

<script setup>
import 'tw-elements';

const props = defineProps({
    marker: {
        type: Object,
        required: true,
    }
});

</script>
<template>
    <div class="accordion-item border-t-0 border-l-0 border-r-0 rounded-none bg-white border border-gray-200">
        <h2 class="accordion-header mb-0" :id="'heading-' + marker.id">
            <button class="
                    accordion-button
                    collapsed
                    relative
                    flex
                    items-center
                    w-full
                    py-4
                    px-5
                    text-base text-gray-800 text-left
                    bg-white
                    border-0
                    rounded-none
                    transition
                    focus:outline-none" type="button" data-bs-toggle="collapse" :data-bs-target="'#' + marker.id"
                aria-expanded="true" :aria-controls="marker.id">
                {{ marker.headline }}
            </button>
        </h2>
        <div :id="marker.id" class="accordion-collapse border-0 collapse" :aria-labelledby="'heading-' + marker.id"
            data-bs-parent="#accordionFlushExample">
            <div class="accordion-body py-4 px-5">
                {{ marker.text }}
            </div>
        </div>
    </div>
</template>

We define a prop here called marker. This prop is being used to get data into the accordion headline and the text under the headline. Let's create the MarkerList Component next.

MarkerList Component

In our Map, we wanna use a custom Marker. There are a couple of SVG Libraries to get good icons from. I'm going to use the location icon from ionic icons.

We create a public/img directory where we place our icons.
Our MarkerList component then looks like this:

<script setup>
import { CustomMarker } from 'vue3-google-map';

const props = defineProps({
    marker: {
        type: Object,
        required: true,
    }
});

</script>

<template>
    <CustomMarker
        :options="{ position: { lat: marker.lat, lng:  marker.lng }, anchorPoint: 'CENTER' }">
        <img src="/img/marker.svg" width="50" height="50" />
    </CustomMarker>
</template>

We wanna get the position from the prop here as well. So we defined a marker prop.

Google Map

In our maps component, we now make use of our accordion and our MarkerList. Creating a Google Map works out of the box after installing Vue 3 - Google Map.

You need your Google Maps API Key to make the map work at all.

Our component could look like this:

<script setup>
import { GoogleMap, MarkerCluster } from 'vue3-google-map';
const locations = ref({
    FCB: {
        id: 'FCB',
        headline: 'FC Bayern München',
        text: 'Bayern München is the most successful soccer club in Germany. In the german Bundesliga their current rank is #1. Add some more text for this item to make it look bigger',
        lat: 48.21888549557031,
        lng: 11.625109549171704
    },
    SCF: {
        id: 'SCF',
        headline: 'SC Freiburg',
        text: 'SC Freiburg is also a german soccer club from the 1. Bundesliga in Germany. In the german Bundesliga their current rank is #2. Add some more text for this item to make it look bigger',
        lat: 48.021196964093434,
        lng: 7.82996300258625
    },
    RBL: {
        id: 'RBL',
        headline: 'Red Bull Leipzig',
        text: 'Red Bull Leipzig is a very good soccer club as well. They are sponsered by Red Bull I guess. In the german Bundesliga their current rank is #3. Add some more text for this item to make it look bigger',
        lat: 51.34762220651972,
        lng: 12.35519705573161
    },
    FCUB: {
        id: 'FCUB',
        headline: 'Union Berlin',
        text: 'This is a soccer club from Berlin. I dont know anything about soccer but here is more text. In the german Bundesliga their current rank is #5. Add some more text for this item to make it look bigger',
        lat: 52.45755304910101,
        lng: 13.568600380052235
    },
    BVB: {
        id: 'BVB',
        headline: 'BVB Borussia Dortmund',
        text: 'BVB is also pretty good soccer club right? They are colored in yellow and black and I thats all I know. In the german Bundesliga their current rank is #6. Add some more text for this item to make it look bigger',
        lat: 51.492787217050754,
        lng: 7.452501674962833
    }
});
const zoom = ref(6);
const center = ref({ lat: 51.075857938487424, lng: 10.313596029890055 })
function zoomEvent(item) {
    center.value = { lat: item.lat, lng: item.lng };
    zoom.value = 15;
}
</script>
<template>
    <ClientOnly>
        <h2 class="text-4xl text-center container mx-auto p-10"> Nuxt 3 - Google Map</h2>
        <div class="w-full grid grid-cols-1 lg:grid-cols-2 gap-8">
            <GoogleMap api-key="YOUR API KEY HERE" class="map" :center="center" :zoom="zoom">
                <MarkerCluster :options="{ position: center }">
                    <div v-for="marker in locations">
                        <MarkerList :marker="marker" />
                    </div>
                </MarkerCluster>
            </GoogleMap>
            <div class="accordion accordion-flush" id="accordionFlushExample">
                <div v-for="marker in locations">
                    <div @click="zoomEvent(marker)">
                        <Accordion :marker="marker" />
                    </div>
                </div>
            </div>
        </div>
    </ClientOnly>
</template>

<style scoped>
.map {
    position: relative;
    width: 100%;
    height: 650px;
}
</style>

We need to import the Google Map components to make it work. Also, we need to give the map a height. Then we create a location object with all data that we need.

In our locations ref there are a couple of soccer clubs. That's very static but this would also work if you would get the data from a WordPress or Typo3 or any Backend.

In the Google Map component, we have the two props zoom and center. That are also the props we need to zoom to one specific location.

Adding the MarkerCluster

In our locations ref we have multiple locations and we want to display them on a map. That's possible with the MarkerCluster component which also comes from the Vue 3 - Google Map.

All we need to do is to loop through the locations and add our MarkerList the component into the MarkerCluster. So a better name for the MarkerList probably would be CustomMarker. Here is the code again:

 <MarkerCluster :options="{ position: center }">
    <div v-for="marker in locations">
        <MarkerList :marker="marker" />
    </div>
</MarkerCluster>

Adding the Accordion

Also, let's take a look at the Accordion part real quick. The Accordion component needs a parent wrapper so we have to put a <div> around it before we render it.

<div class="accordion accordion-flush" id="accordionFlushExample">
    <div v-for="marker in locations">
        <div @click="zoomEvent(marker)">
            <Accordion :marker="marker" />
        </div>
    </div>
</div>

Here we also need the function to zoom to the selected marker.

We already have two properties that we need to change on a click event. We do that by overriding the value like this:

function zoomEvent(item) {
    center.value = { lat: item.lat, lng: item.lng };
    zoom.value = 15;
}

That's it! You also could improve it by zooming back if you close an element from the collapse but we have created what we wanted to.

Conclusion

We created a custom Google Map component with custom Markers. On our map, there are multiple markers and we zoom into the markers on a click event. I think that's pretty cool right?

If you have a store in multiple locations this could be very useful. Or for a sports website with multiple important locations. Make sure to use your Google Maps API Key to make it work.

You can take a look at the code on my GitHub. Thanks a lot for reading!

Did you find this article valuable?

Support Joschi by becoming a sponsor. Any amount is appreciated!