Skip to main content
← Blog

Adding a Sense of Place to Your Tasks

VauDium ·

Building address autocomplete with Apple Maps API, map previews, and the unexpected TextInput bug along the way.

Adding a Sense of Place to Your Tasks

Fecit always had a location field. A simple text box where you could type anything — “Gangnam Starbucks,” “home,” whatever you wanted. Free-form, no structure.

But sometimes you want the actual address. A meeting spot you’ve never been to, or a place you need to navigate to later. Switching to a maps app, copying the address, and pasting it back felt like too many steps for something that should be seamless.

So I decided to add autocomplete.

Why Apple Maps

Google Maps comes to mind first, but the free tier is limited and requires billing setup. Apple Maps Server API offers 250,000 requests per day for free with solid global coverage. And since the app runs on both iOS and Android, a platform-agnostic API was important too.

One thing that tripped me up was the authentication. I assumed you just send a JWT and you’re done. Turns out, Apple Maps Server API uses a two-step flow: first you exchange your JWT for an access token, then you use that token for the actual API calls. I spent a while staring at 401 errors, checking my key configuration in Apple Developer Portal over and over, before realizing the auth flow itself was different from what I expected.

Server Proxy

You can’t put API keys in the app, so the architecture goes through a server.

App → FastAPI Server → Apple Maps Server API

The server generates JWTs, caches access tokens for 30 minutes, and the app just calls our own API. Simple, once you understand the two-step dance.

Autocomplete UI

I used a 300ms debounce, triggering search after 2 characters. The dropdown follows the same pattern as the existing template recommendation dropdown — results appear below the input, tap one to fill in the address.

Then I ran into an unexpected problem.

The TextInput That Wouldn’t Grow

When you select a long address from autocomplete, the text wraps to multiple lines. With multiline enabled, the input should grow taller. It didn’t.

The strange part: if you manually deleted even one character, it would suddenly snap to the correct height.

This turned out to be a known issue with React Native’s iOS New Architecture (Fabric). When you set the value prop programmatically, the native TextInput doesn’t recalculate its intrinsic content size. Manual edits go through the native text editing flow which triggers the recalculation, but JS-driven value changes take a different code path that skips it.

The fix was to render an invisible Text component with the same content, use onTextLayout to count the actual number of lines, and set the TextInput’s minHeight accordingly. A workaround, but a reliable one.

Saving Coordinates and Map Preview

Apple Maps returns coordinates in its autocomplete response. It felt wasteful to throw them away. So I added addressLatitude and addressLongitude fields to the Task model.

When coordinates exist, a small map preview appears below the address input — a 100px react-native-maps view with a marker. Tap it, and you get a full-screen map.

Clear the address text, and the coordinates go with it. The map disappears. If you type an address manually instead of using autocomplete, there are no coordinates, so no map. It’s a nice bonus that comes naturally from using the autocomplete.

My first search for “Gangnam” returned a restaurant in Los Angeles. Without knowing where the user is, Apple Maps searches globally.

Adding expo-location to send the device’s current coordinates with each search request fixed this. Search from Korea, get Korean results. If location permission is denied, search still works — the results are just less locally relevant.

Looking Back

What I thought would be simple autocomplete turned into authentication debugging, a TextInput rendering bug, coordinate storage, and location-based search tuning. More steps than expected.

But I’m happy with the result. There’s something satisfying about selecting an address and seeing a little map appear. A task with a place attached to it feels more concrete. “Prepare presentation” is abstract. “Prepare presentation at Gangnam Starbucks” — that’s something you can picture.


When a task has a place, it becomes a little more real.