Design+Code logo

Quick links

Suggested search

CodeSandbox link

You can find the full code for this tutorial at https://codesandbox.io/s/geocoding-with-mapbox-4cst8.

Create an account

Before learning how to use the Mapbox Geocoding API, the first thing we need to do is to create an account on Mapbox. Their free tier (for Temporary Geocoding API, meaning that the search results won't be saved) is quite generous: you get up to 100 000 free monthly requests. You can explore the pricing for other ranges of monthly requests on their pricing page.

Mapbox home page Once signed up, you should land on your dashboard. This is where you can generate your access tokens in order to query the Mapbox API.

Mapbox Account dashboard

Generate an access token

On your dashboard, scroll down to the Access tokens section and copy the Default public token or generate a new one. We'll need it later.

Mapbox Access tokens

Create the input field

Code the input field in which we'll apply the address autocomplete feature. You can code your own or use the one below.

// inputField.js

import React from "react";
import styled from "styled-components";

const InputField = () => {
  return (
    <Wrapper>
      <Input placeholder="Address" />
    </Wrapper>
  );
};

export default InputField;

const Wrapper = styled.div`
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  margin: 0 auto;
`;

const Input = styled.input`
  width: 400px;
  background: white;
  border: none;
  padding: 10px 20px;
  border-radius: 30px;
  position: relative;
  display: grid;
  justify-self: center;
  &:focus {
    outline: none;
  }
`;

const SuggestionWrapper = styled.div`
  background: white;
  position: absolute;
  width: 400px;
  padding: 10px 20px;
  border-radius: 0px 0px 10px 10px;
`;

const Suggestion = styled.p`
  cursor: pointer;
  max-width: 400px;
`;

Import the useInput hook

Since we want to create an address autocomplete onChange of the text the user inputs, we'll simply use the useInput hook from the useInput Hook section of this handbook and add a few lines of code to it. The code below is the default useInput hook. Let's add it to our project.

// useInput.js

import { useState } from "react";

const useInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);

  const handleChange = async (event) => {
    setValue(event.target.value);
  };

  return {
    value,
    onChange: handleChange,
  };
};

export default useInput;

Connect useInput with the input

Head over to the InputField.js file, or the file that contains your input field, and import useInput hook at the top.

// InputField.js

import useInput from "./useInput";

Create a new variable where we'll save the address, and call the useInput hook. The initial value is an empty string.

// InputField.js

const address = useInput("");

On your input, spread the address . This is a shorthand for writing two lines of code to set the value and the onChange event of the input.

// InputField.js

<Input
	placeholder="Address"
	{...address}
/>

Update the useInput hook

Now, let's update our useInput hook in order to integrate the address autocomplete suggestions. Create a new useState below the value useState , and call it suggestions.

// useInput.js

const [suggestions, setSuggestions] = useState([]);

Inside of the handleChange function, we'll need to add a few lines of code. First, after setting the value, create the endpoint URL.

// useInput.js

const endpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${event.target.value}.json?access_token=${your_access_token}&autocomplete=true`;

The URL can be broken down into six parts:

  • The base URL, https://api.mapbox.com
  • The service we're using, version 5 of the Geocoding API (/geocoding/v5).
  • The API endpoint we want to target is /mapbox.places. The other option is /mapbox.places-permanent, if you want to permanently save your search results.
  • The search text, which is what the user inputs in the text field. We can access it through event.target.value. In the URL, we need to add .json to get the JSON object in return.
  • We need to provide our access token we copied before, so paste it here. For the purposes of this tutorial, we're hard-coding it in our URL, but remember to never hard-code your access tokens if you're sharing your project or committing it to Github, as it is a big security flaw.
  • Finally, we need to set autocomplete to true, so that the API returns us an array of suggestions that starts with the characters the user inputs. Once we have our URL, we'll use the built-in fetch function and await the response . When we get the response, we'll use the .json() function to convert the response to JSON. Finally, if we get results and a features array inside of the results JSON object, we'll set it to the suggestions state we created. We also need to wrap the fetch function in a try catch statement, in case it raises an error.
// useInput.js

const handleChange = async (event) => {
  setValue(event.target.value);

  try {
	  const endpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${event.target.value}.json?access_token=pk.eyJ1Ijoic3RoeW1hIiwiYSI6ImNrcnFycDlzNjFxM3Uydm1vMGNxd200amsifQ.aTXBxeiEvrCesxbO8OuFEg&autocomplete=true`;
    const response = await fetch(endpoint);
    const results = await response.json();
    setSuggestions(results?.features);
  } catch (error) {
    console.log("Error fetching data, ", error);
  }
};

In the return statement of our useInput hook, we'll return a few more items. Besides the value and the onChange event, we'll also return the setValue function, the suggestions array, and the setSuggestions function, as we'll need them all in InputField.

// useInput.js

return {
	value,
	onChange: handleChange,
	setValue,
	suggestions,
	setSuggestions
};

Add the suggestions to the UI

In InputField.js , right below the input, we'll iterate over the suggestions array from the address variable. First, we want to make sure that the array contains at least one element.

// InputField.js

{address.suggestions?.length > 0 && <div></div>}

Then, let's map through the suggestions array if it's populated. Don't forget to provide a key for each paragraph you're creating inside of your map function, as each child element in a map should have a unique key.

// InputField.js

{address.suggestions?.length > 0 && (
	<div>
		{address.suggestions.map((suggestion, index) => {
				return (
						<p key={index}>
						{suggestion.place_name}
						</p>
				);
		})}
	</div>
)}

On click of the paragraph, we want to set the address' value to the suggestion the user clicked on, so let's add address.setValue(suggestion.place_name) to the onClick event. We also want to reset the suggestions array to an empty array once the user clicked on a suggestion, so let's also add address.setSuggestions([]).

// InputField.js

<p
	key={index}
	onClick={() => {
		address.setValue(suggestion.place_name);
		address.setSuggestions([])
	}}
>
{suggestion.place_name}
</p>

Final code

Below is the final code for the inputField.js file.

// inputField.js

import React from "react";
import styled from "styled-components";
import useInput from "./useInput";

const InputField = () => {
  const address = useInput("");

  return (
    <Wrapper>
      <Input
        placeholder="Address"
        {...address}
        isTyping={address.value !== ""}
      />
      {address.suggestions?.length > 0 && (
        <SuggestionWrapper>
          {address.suggestions.map((suggestion, index) => {
            return (
              <Suggestion
                key={index}
                onClick={() => {
                  address.setValue(suggestion.place_name);
                  address.setSuggestions([]);
                }}
              >
                {suggestion.place_name}
              </Suggestion>
            );
          })}
        </SuggestionWrapper>
      )}
    </Wrapper>
  );
};

export default InputField;

const Wrapper = styled.div`
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  margin: 0 auto;
`;

const Input = styled.input`
  width: 400px;
  background: white;
  border: none;
  padding: 10px 20px;
  border-radius: 30px;
  position: relative;
  display: grid;
  justify-self: center;
  &:focus {
    outline: none;
    border-radius: ${(props) => props.isTyping && "10px 10px 0px 0px"};
  }
`;

const SuggestionWrapper = styled.div`
  background: white;
  position: absolute;
  width: 400px;
  padding: 10px 20px;
  border-radius: 0px 0px 10px 10px;
`;

const Suggestion = styled.p`
  cursor: pointer;
  max-width: 400px;
`;

Learn with videos and source files. Available to Pro subscribers only.

Purchase includes access to 50+ courses, 320+ premium tutorials, 300+ hours of videos, source files and certificates.

BACK TO

Serverless Email Sending

READ NEXT

Contentful Part 1

Templates and source code

Download source files

Download the videos and assets to refer and learn offline without interuption.

check

Design template

check

Source code for all sections

check

Video files, ePub and subtitles

Browse all downloads