---
title: Bitovi Academy - Map View
description: Create a component to hold our Google map view. This lesson carries over from the last and will use the same CodePen.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React Native ](https://www.bitovi.com/academy/learn-react-native.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us) 
    - [ Why Web Components ](https://www.bitovi.com/academy/learn-web-components/why-wc.html?hsLang=en-us)
    - [ Our first component ](https://www.bitovi.com/academy/learn-web-components/first-component.html?hsLang=en-us)
    - [ Writing a template ](https://www.bitovi.com/academy/learn-web-components/templates.html?hsLang=en-us)
    - [ Map View ](https://www.bitovi.com/academy/learn-web-components/map-view.html?hsLang=en-us)
    - [ bus-tracker component ](https://www.bitovi.com/academy/learn-web-components/bus-tracker-component.html?hsLang=en-us)
    - [ Listing routes ](https://www.bitovi.com/academy/learn-web-components/listing-routes.html?hsLang=en-us)
    - [ Selecting a route ](https://www.bitovi.com/academy/learn-web-components/select-a-route.html?hsLang=en-us)
    - [ Display markers for vehicles ](https://www.bitovi.com/academy/learn-web-components/display-markers.html?hsLang=en-us)
    - [ Customize header styles ](https://www.bitovi.com/academy/learn-web-components/customize-header.html?hsLang=en-us)
    - [ Slotted content ](https://www.bitovi.com/academy/learn-web-components/slotted-content.html?hsLang=en-us)
    - [ Dispatching events ](https://www.bitovi.com/academy/learn-web-components/dispatching-events.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Map View `page`

Create a component to hold our Google map view. This lesson carries over from the last and will use the same CodePen.

## Overview

In this part we will:

- Create a custom element named `google-map-view`.
- Initialize the [Google maps API](https://developers.google.com/maps/documentation/).
- Learn about Shadow DOM and `connectedCallback`.

## Problem

Create a component where we can display a Google map. Google maps need to be attached to a DOM element, so use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate the HTML and CSS that Google maps builds.

![google-map-view component with a useable slippy map.](https://bitovi.github.io/academy/static/img/web-components/gmap-slippy.gif)

## How to Solve This Problem

1. Add the `script` element for the Google map API.
2. Create a custom element that contains a Shadow DOM with the contents from the `template` in the previous exercise.
3. Set up the Google map *only* when the custom element is connected to the DOM.

## Technical requirements

Use the existing `#gmap-template` template, and append it to the host component’s Shadow DOM. Use this script tag to enable the Google maps API:

```
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD7POAQA-i16Vws48h4yRFVGBZzIExOAJI"></script>
```

This snippet will create a Map centered on Chicago:

```
new google.maps.Map(element, {
  zoom: 10,
  center: {
    lat: 41.881,
    lng: -87.623
  }
});
```

Where `element` is the element the Google map will mount to.

## What you need to know

- How to create Shadow DOM for an element.
- Which callback to use to instantiate a new `Map` for the Google map.

### Shadow DOM

(Most) elements can have a `shadowRoot` property. This is a special version of a [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) that is completely encapsulated. You cannot query the nodes within it from the outside (like `document.querySelector('.gmap')`). Styles within will not affect DOM outside.

You can create a `shadowRoot` for your element by calling [attachShadow](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow).

```
<template>
  <p>Hello there</p>
</template>
<script type="module">
let template = document.querySelector('template');
let fragment = document.importNode(template.content, true);

let el = document.createElement('div');
el.attachShadow({ mode: 'open' });
el.shadowRoot.append(fragment);

document.body.append(el);
</script>
```

You can create **closed** shadowRoots by using `{ mode: 'closed' }`. When you do this, the `shadowRoot` property will not be added to the element. To be able to append items to the shadowRoot, keep a reference to it from the return value of `attachShadow()`.

```
<template>
  <p>Hello from a closed shadow</p>
</template>
<script type="module">
let template = document.querySelector('template');
let fragment = document.importNode(template.content, true);

let el = document.createElement('div');
let shadow = el.attachShadow({ mode: 'closed' });

console.log(el.shadowRoot); // -> null

shadow.append(fragment);
document.body.append(el);
</script>
```

### connectedCallback

For elements with side-effects (such as those that make network requests), it’s best to do those side effects in the **connectedCallback**.

`connectedCallback` is a lifecycle method for custom elements. It is called when the element is **connected**, which can occur in one of these scenarios:

- The HTML parser sees the element within the page.
- An element node is inserted into the page like `document.body.append(node)`.

The `connectedCallback` method will be called *each time* the element is inserted. If an element is inserted, removed, and reinserted, the `connectedCallback` will be called twice.

```
<my-element></my-element>

<script type="module">
class MyElement extends HTMLElement {
  constructor() {
    super();
    this.timesConnected = 0;
  }

  connectedCallback() {
    this.timesConnected++;
    console.log('Connected', this.timesConnected, 'times');
  }
}

customElements.define('my-element', MyElement);

let el = document.querySelector('my-element');

el.remove();
document.body.append(el);
el.remove();
document.body.append(el);
</script>
```

## Solution

✏️ Building off of the template we created in the previous section, now extend `HTMLElement` to create a custom element.

Click to see the solution

```
<style>
  html,
  body {
    height: 100%;
  }
  body {
    font-family: "Catamaran", sans-serif;
    background-color: #f2f2f2;
    display: flex;
    flex-direction: column;
    margin: 0;
  }
</style>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD7POAQA-i16Vws48h4yRFVGBZzIExOAJI"></script>

<google-map-view></google-map-view>

<template id="gmap-template">
  <style>
    .gmap {
      width: 100%;
      height: 250px;
      background-color: grey;
    }
  </style>
  <div class="gmap"></div>
</template>
<script type="module">
const template = document.querySelector('#gmap-template');

class GoogleMapView extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });

    let frag = document.importNode(template.content, true);
    this.shadowRoot.append(frag);
  }

  connectedCallback() {
    let gmap = this.shadowRoot.querySelector('.gmap');
    this.map = new google.maps.Map(gmap, {
      zoom: 10,
      center: {
        lat: 41.881,
        lng: -87.623
      }
    });
  }
}

customElements.define('google-map-view', GoogleMapView);
</script>

```

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-web-components/map-view.html",
          "description": "Create a component to hold our Google map view. This lesson carries over from the last and will use the same CodePen. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```