Lightweight Google Maps Input for Sanity

Learn how to add a Google Maps Input component to Sanity with live preview.

For a recent project I wanted to add a lightweight Google Maps input to Sanity. There is a plugin that kind of makes this possible. However, the plugin requires a Google Maps API key and it stores the coordinates of the place to embed.

Using coordinates for your Google Maps embed is extra work. Especially when you consider you can simply embed Google Maps by passing a query to the url.

This is much easier:

<iframe
  src="https://maps.google.com/maps?q=Le%20Louvre&z=15&ie=UTF8&output=embed">
</iframe>

Note, the search query is the part after the q param, here «Le%20Louvre». Since URLs cannot contain special characters, – like the space character – we have to encode the URL to replace these special characters with their encoded counterparts. In case of the space character it’s «%20».

Sanity Schema

Concerning the Schema, we only have to store the query describing the place we want to display on the map.

The corresponding schema file is pretty straightforward:

// googleMaps.js

export default {
  name: 'googleMaps',
  title: 'Google Maps',
  type: 'document',
  fields: [
    {
      name: 'address',
      title: 'Address',
      type: 'string',
    },
  ],
}

Custom Sanity Input Component

Now we want to add a preview component, so that the CMS editors can see, if the map embed is working correctly.

For this, create a JSX file:

// mapsPreview.jsx

import { Stack } from '@sanity/ui';

// helper component to render the Iframe
const MapsEmbed = ({ address }) => {
  // encode the address to use it inside the url
  const query = encodeURIComponent(address);
  const url = `https://maps.google.com/maps?q=${query}&z=15&ie=UTF8&output=embed`

  return(
    <iframe
      width="380"
      height="200"
      style={{ width: '100%' }}
      frameBorder="0"
      scrolling="no"
      marginHeight="0"
      marginWidth="0"
      src={url}>
    </iframe>
  )
};

// the actual component to use in the schema
export function MapsPreview(props) {
  // get the address that get's passed to the component
  const {address} = props.value;

  return (
    // use Sanity UI stack, to give some space between the elements
    <Stack space={2}>
        {/* render the default input field */}
        {props.renderDefault(props)}

        {/* only render the Map Embed, if a string is specified */}
        {
          typeof address === 'string' &&
          <MapsEmbed address={address} />
        }
        { typeof address !== 'string' && <span>Enter an address</span> }
    </Stack>
  )
}

Now we can use the component in our googleMaps schema:

+import { MapsPreview } from "./mapsPreview";

export default {
  name: 'googleMaps',
  title: 'Google Maps',
  type: 'document',
  fields: [
    {
      name: 'address',
      title: 'Address',
      type: 'string',
    },
  ],
+  components: {
+    input: MapsPreview,
+  }
}

That’s it! We got a fully working Google Maps embed input in Sanity.

To render the embed inside your website, you can use a similar approach as in the MapsEmbed inside the mapsEmbed.jsx file:

const MapsEmbed = ({ address }) => {
  const query = encodeURIComponent(address);
  const url = `https://maps.google.com/maps?q=${query}&z=15&ie=UTF8&output=embed`

  return(
    <iframe
      width="380"
      height="200"
      style={{ width: '100%' }}
      frameBorder="0"
      scrolling="no"
      marginHeight="0"
      marginWidth="0"
      src={url}>
    </iframe>
  )
};

This post was first published on .