Maps Address Field
Address autocomplete via Cal’s Google Places proxy, with optional free-text fallback.
Address field used for in-person locations, form-builder address questions, and discover business profiles. Production imports the lazy wrapper so Places deps stay out of the initial bundle.
import { GoogleMapsAddress } from "@calcom/features/form/components/google-maps-address-lazy";Ownership
Feature — not @coss/ui/shared. Suggestions come from POST /api/google-places/autocomplete (server-side API key). By default, when Places is unconfigured the field falls back to free text. Discover passes strictPlaces so free-text fallback is disabled and the input locks when Places is unavailable. That proxy contract and validity semantics (onValidityChange) keep it Feature-owned.
Example
Use the lazy Feature import in product code. Discover requires a Places city selection for physical businesses and blocks free-form text when Places is down:
<Field>
<FieldLabel>{t("city")}</FieldLabel>
<GoogleMapsAddress
onChange={(value) => form.setAddress(value)}
onValidityChange={form.setIsAddressValid}
placeFilter="city"
placeholder={t("discover_onboarding_city_placeholder")}
required={!form.isOnlineBusiness}
strictPlaces
value={form.address}
/>
{!form.isOnlineBusiness && form.address.trim().length > 0 && !form.isAddressValid ? (
<p className="text-destructive text-xs" data-testid="discover-address-invalid">
{t("discover_city_requires_selection")}
</p>
) : null}
</Field>This is the canonical composition when place confirmation matters — Discover wires onValidityChange + strictPlaces. Event-type in-person address (LocationInput) and booking edit-location omit validity gating and wire the field through React Hook Form Controller. The real component owns debouncing, request cancellation, suggestion caching, Places attribution, and (by default) free-text fallback when the proxy is unconfigured.
API
| Prop | Type | Notes |
|---|---|---|
value | string | Current address text |
onChange | (val: string) => void | Input / selection updates |
onValidityChange | (isValidPlace: boolean) => void | Gate submit when a confirmed place is required |
placeFilter | "address" | "city" | Restricts Google suggestions (city → (cities)) |
strictPlaces | boolean | No free-text fallback; disables input when Places is unavailable |
onPlacesAvailabilityChange | (available: boolean) => void | Places usable vs unconfigured/failed |
placeholder | string | Input placeholder |
required | boolean | Native required |
disabled | boolean | Disables the field |
id / name | string | Form wiring |
className | string | Input classes |
Implementation lives in google-maps-address.tsx; product code should import google-maps-address-lazy.
Call sites
| File | Notes |
|---|---|
apps/web/modules/event-types/components/locations/LocationInput.tsx | In-person organizer address |
apps/web/components/dialog/EditLocationDialog.tsx | Booking edit-location address |
apps/web/modules/form-builder/components/Components.tsx | Form-builder address field |
apps/web/modules/discover/components/business-profile-form.tsx | Discover business address + validity gate |
Example URLs
Not exhaustive — a few places you can open locally (e.g. http://localhost:3000) to see this in product.
| Path | Notes |
|---|---|
/event-types/<eventTypeId>?tabName=setup | In-person organizer address |
/settings/discover/my-business | Discover business address |
/bookings/upcoming | Edit location address — opens in dialog |
Source
- Lazy (public):
google-maps-address-lazy.tsx - Implementation:
google-maps-address.tsx
On This Page