Skip to main content

User Experience (UX)

Invoke the Mapbox Geocoding API to Populate the Location Autocomplete Functionality

Location City Map Street Navigation Of Road Town Travel Gps District Direction Symbol Or Cartography Transportation Route Sign And Downtown Navigator Geography System On Positioning 3d Background.

While working on one of my projects, I needed to implement an autocomplete box using Mapbox Geocoding APIs in a React/Next.js application. The goal was to filter a list of hospitals based on the selected location. The location results from the API include coordinates, which I compared with the coordinates of the hospitals in my list.

The API returns various properties, including coordinates, under the properties section (as shown in the image below). These coordinates (latitude and longitude) can be used to filter the hospital list by matching them with the selected location.

Mapboxresultproperties

The API requires an access token, which can be obtained by signing up on the Mapbox platform. You can refer to the Geocoding API documentation for more details. The documentation provides a variety of APIs that can be used depending on your specific requirements.

Below are some example APIs taken from the same link.

# A basic forward geocoding request
# Find Los Angeles

curl "https://api.mapbox.com/search/geocode/v6/forward?q=Los%20Angeles&access_token=YOUR_MAPBOX_ACCESS_TOKEN"

# Find a town called 'Chester' in a specific region
# Add the proximity parameter with local coordinates
# This ensures the town of Chester, New Jersey is in the results

curl "https://api.mapbox.com/search/geocode/v6/forward?q=chester&proximity=-74.70850,40.78375&access_token=YOUR_MAPBOX_ACCESS_TOKEN"

# Specify types=country to search only for countries named Georgia
# Results will exclude the American state of Georgia

curl "https://api.mapbox.com/search/geocode/v6/forward?q=georgia&types=country&access_token=YOUR_MAPBOX_ACCESS_TOKEN"

# Limit the results to two results using the limit option
# Even though there are many possible matches
# for "Washington", this query will only return two results.

curl "https://api.mapbox.com/search/geocode/v6/forward?q=Washington&limit=2&access_token=YOUR_MAPBOX_ACCESS_TOKEN"

# Search for the Place feature "Kaaleng" in the Ilemi Triangle. Specifying the cn worldview will return the country value South Sudan. Not including leaving the worldview parameter would default to the us worldview and return the country value Kenya.

curl "https://api.mapbox.com/search/geocode/v6/forward?q=Kaaleng&worldview=cn&access_token=YOUR_MAPBOX_ACCESS_TOKEN"

The implementation leverages React hooks along with state management for handling component behavior and data flow.

How to Create an Autocomplete Component in React

  1. Create a React component.
  2. Sign up and apply the access token and API URL to the constants.
  3. Create a type to bind the structure of the API response results.
  4. Use the useEffect hook to invoke the API.
  5. Map the fetched results to the defined type.
  6. Apply CSS to style the component and make the autocomplete feature visually appealing.
#constants.ts

export const APIConstants = {
  accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
  geoCodeSearchForwardApiUrl: 'https://api.mapbox.com/search/geocode/v6/forward',
  searchWordCount: 3,
};
#LocationResultProps.ts

type Suggetions = {
  properties: {
    feature_type: string;
    full_address: string;
    name: string;
    name_preferred: string;
    coordinates: {
      longitude: number;
      latitude: number;
    };
  };
};
export type LocationResults = {
  features: Array<Suggetions>;
};
#Styles.ts

export const autoComplete = {
  container: {
    width: '250px',
    margin: '20px auto',
  },
  input: {
    width: '100%',
    padding: '10px',
    fontSize: '16px',
    border: '1px solid #ccc',
    borderRadius: '4px',
  },
  dropdown: {
    top: '42px',
    left: '0',
    right: '0',
    backgroundColor: '#fff',
    border: '1px solid #ccc',
    borderTop: 'none',
    maxHeight: '150px',
    listStyleType: 'none',
    padding: '0',
    margin: '0',
    zIndex: 1000,
  },
  item: {
    padding: '5px',
    cursor: 'pointer',
    borderBottom: '1px solid #eee',
  },
};

#LocationSearchInput.tsx

import React, { useEffect, useState } from 'react';
import { APIConstants } from 'lib/constants';
import { autoComplete } from '../Styles';
import { LocationResults } from 'lib/LocationResultProps';

export const Default = (): JSX.Element => {
  const apiUrlParam: string[][] = [
    //['country', 'us%2Cpr'],
    ['types', 'region%2Cpostcode%2Clocality%2Cplace%2Cdistrict%2Ccountry'],
    ['language', 'en'],
    //['worldview', 'us'],
  ];

  const [inputValue, setInputValue] = useState<string>('');
  const [results, setresults] = useState<LocationResults>();
  const [submitted, setSubmitted] = useState<boolean>(false);

  // When the input changes, reset the "submitted" flag.
  const handleChange = (value: string) => {
    setSubmitted(false);
    setInputValue(value);
  };
  const handleSubmit = (value: string) => {
    setSubmitted(true);
    setInputValue(value);
  };

  // Fetch results when the input value changes
  useEffect(() => {
    if (inputValue.length < APIConstants?.searchWordCount) {
      setresults(undefined);
      return;
    }
    if (submitted) {
      return;
    }
    const queryInputParam = [
      ['q', inputValue],
      ['access_token', APIConstants?.accessToken ?? ''],
    ];

    const fetchData = async () => {
      const queryString = apiUrlParam
        .concat(queryInputParam)
        .map((inner) => inner.join('='))
        .join('&');
      const url = APIConstants?.geoCodeSearchForwardApiUrl + '?' + queryString;

      try {
        const response: LocationResults = await (await fetch(url)).json();
        setresults(response);
        console.log(response);
      } catch (err: unknown) {
        console.error('Error obtaining location results for autocomplete', err);
      }
    };

    fetchData();
  }, [inputValue]);

  return (
    <div>
      <div style={autoComplete.container}>
        <input
          style={autoComplete.input}
          onChange={(e) => handleChange(e.target?.value)}
          value={inputValue}
          placeholder="Find Location"
        />

        {inputValue &&
          !submitted &&
          results?.features?.map((x) => {
            return (
              <ul style={autoComplete.dropdown}>
                <li style={autoComplete.item}>
                  <span onClick={() => handleSubmit(x?.properties?.full_address)}>
                    {x?.properties?.full_address}
                  </span>
                </li>
              </ul>
            );
          })}
      </div>
    </div>
  );
};

Finally, we can search for a location using a zip code, state, or country.

Recording 20250520 135312 (1)

 

Additionally, the reverse geocoding API is used similarly, requiring only minor adjustments to the parameters and API URL. The location autocomplete box offers a wide range of use cases. It can be integrated into user forms such as registration or contact forms, where exact location coordinates or a full address need to be captured upon selection. Each location result includes various properties. Based on the user’s input, whether it’s a city, ZIP code, or state, the autocomplete displays matching results.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Parag Balapure

Parag Balapure is a senior technical consultant at Perficient who has contributed eight years in ASP.Net MVC, Sitecore (9.x and 10.x), Sitecore Headless Development, SXA, C#, SQL, along with front-end technologies like ReactJS, VueJS, and others. He likes investigating and solving complex technical problems.

More from this Author

Follow Us