Skip to content

Instantly share code, notes, and snippets.

@AmitMirgal
Created April 14, 2024 19:10
Show Gist options
  • Save AmitMirgal/34473f99d1e3c9037c03a6941619f25b to your computer and use it in GitHub Desktop.
Save AmitMirgal/34473f99d1e3c9037c03a6941619f25b to your computer and use it in GitHub Desktop.
React component that uses forward geocoding from the Mapbox service. You can copy and paste this into your app code, styled with TailwindCSS
/*
This example requires some changes to your config:
```
import tailwindCSSForms from "@tailwindcss/forms";
// tailwind.config.js
export default {
// ...
plugins: [
// ...
tailwindCSSForms,
],
}
```
*/
import {
useState,
useDeferredValue,
useEffect,
startTransition,
memo,
} from "react";
import { Combobox } from "@headlessui/react";
import { ChevronUpDownIcon, CheckIcon } from "@heroicons/react/20/solid";
import { clsx } from "clsx";
type AddressType = {
properties: {
name: string;
full_address: string;
};
[key: string]: AddressType | unknown;
};
function classNames(...classes: Array<string | boolean>) {
return classes.filter(Boolean).join(" ");
}
const SearchResults = memo(function SearchResults({
query,
}: {
query: string;
}) {
const [address, setAddress] = useState<AddressType[]>([]);
const filteredAddress =
query === ""
? address
: address.filter((address: AddressType) => {
return address.properties.name
.toLowerCase()
.includes(query.toLowerCase());
});
useEffect(() => {
const searchPlaces = async () => {
const encodedQuery = encodeURIComponent(query);
const res = await fetch(
`https://api.mapbox.com/search/geocode/v6/forward?q=${encodedQuery}&access_token=${import.meta.env.VITE_MAPBOX_API_KEY}`,
);
const result = await res.json();
startTransition(() => {
setAddress(result?.features);
});
};
if (query !== "") {
searchPlaces();
}
}, [query]);
if (query === "") {
return null;
}
if (address.length === 0) {
return (
<p className="mt-2">
No matches for <b>"{query}"</b>
</p>
);
}
return (
<>
{filteredAddress.length > 0 && (
<Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{filteredAddress.map((address: AddressType) => (
<Combobox.Option
key={address.properties.name}
value={address}
className={({ active }) =>
classNames(
"relative cursor-default select-none py-2 pl-3 pr-9",
active ? "bg-indigo-600 text-white" : "text-gray-900",
)
}
>
{({ active, selected }) => (
<>
<span
className={classNames(
"block truncate",
selected && "font-semibold",
)}
>
{address.properties.full_address}
</span>
{selected && (
<span
className={classNames(
"absolute inset-y-0 right-0 flex items-center pr-4",
active ? "text-white" : "text-indigo-600",
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
)}
</>
)}
</Combobox.Option>
))}
</Combobox.Options>
)}
</>
);
});
export default function AddressLookup({ className }: { className?: string }) {
const [query, setQuery] = useState("");
const deferredQuery = useDeferredValue(query);
const [selectedAddress, setSelectedAddress] = useState<AddressType | null>(
null,
);
return (
<div className={clsx([className, "col-span-full"])}>
<div className="mt-1">
<Combobox
as="div"
name="address"
value={selectedAddress}
onChange={setSelectedAddress}
>
<Combobox.Label className="block text-sm font-medium leading-6 text-gray-900">
Address
</Combobox.Label>
<div className="relative mt-2">
<Combobox.Input
className="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-10 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
onChange={(event) => setQuery(event.target.value)}
displayValue={(address: AddressType) =>
address?.properties?.full_address
}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</Combobox.Button>
<SearchResults query={deferredQuery} />
</div>
</Combobox>
</div>
</div>
);
}
@AmitMirgal
Copy link
Author

AddressLookup

React component that uses forward geocoding from the Mapbox service. You can copy and paste this into your app code, styled with TailwindCSS

Run the following command

# required packages
npm install @headlessui/react @heroicons/react clsx @tailwindcss/forms

Update tailwind.config.js

Add the following @tailwindcss/forms to your tailwind.config.js file:

tailwind.config.js

import tailwindCSSForms from "@tailwindcss/forms";

export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: { },
  plugins: [tailwindCSSForms],
};

Tip

Please comment if I missed anything out. Happy coding 🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment