Places Details Component

The Place Details component of the Places UI Kit lets you add an individual UI component that displays place details in your app.

Place details compact component

The PlaceDetailsCompactFragment renders details for a selected place using minimal space. This may be useful in an info window highlighting a place on a map, in a social media experience like sharing a location in a chat, as a suggestion for selecting your current location, or within a media article to reference the place on Google Maps. The PlaceDetailsCompactFragment can display name, address, rating, type, price, accessibility icon, open status, and a single photo.

The Place Details component can be used independently or in conjunction with other Google Maps Platform APIs and services. The component takes either a Place ID or latitude/longitude coordinates and returns rendered Place Details information.

Billing

When using the Place Details UI Kit, you are billed for each time the .loadWithPlaceId() or the .loadWithResourceName() method is called. If you load the same place multiple times, you are billed for each request.

To avoid being charged multiple times, don't directly add .loadWithPlaceId() or .loadWithResourceName()in Android lifecycle methods. For example, don't directly call .loadWithPlaceId() or .loadWithResourceName()in the onResume() method.

Add place details to your app

You can add place details to your app by adding a fragment to a layout. When you instantiate the fragment, you can customize the look and feel of the place details information to suit your needs and match your app's appearance.

You have two methods available in both Kotlin and Java: one to load the fragment with a Place ID (loadWithPlaceId()) and one to load the fragment with a resource name (loadWithResourceName()). You can choose either method, or both if you are using both place IDs and resource names.

You can specify orientation (horizontal or vertical), theme overrides, and content. The content options are media, address, rating, price, type, accessible entrance, and open now status. Learn more about customization.

Kotlin

val fragment = PlaceDetailsCompactFragment.newInstance(
  orientation,
  listOf(Content.ADDRESS, Content.TYPE, Content.RATING, Content.ACCESSIBLE_ENTRANCE_ICON),
  R.style.CustomizedPlaceDetailsTheme,
)
      
fragment.setPlaceLoadListener(object : PlaceLoadListener {
  override fun onSuccess(place: Place) { ... }
      
  override fun onFailure(e: Exception) { ... }
})
      
supportFragmentManager
  .beginTransaction()
  .add(R.id.fragment_container, fragment)
  .commitNow()
      
// Load the fragment with a Place ID.
fragment.loadWithPlaceId(placeId)
// Load the fragment with a resource name.
//fragment.loadWithResourceName(resourceName)

Java

      
PlaceDetailsCompactFragment fragment =
  PlaceDetailsCompactFragment.newInstance(
        Orientation.HORIZONTAL,
        Arrays.asList(Content.ADDRESS, Content.TYPE, Content.RATING, Content.ACCESSIBLE_ENTRANCE_ICON),
        R.style.CustomizedPlaceDetailsTheme);
    
fragment.setPlaceLoadListener(
  new PlaceLoadListener() {
        @Override public void onSuccess(Place place) { ... }
    
        @Override public void onFailure(Exception e) { ... }
});
    
getSupportFragmentManager()
      .beginTransaction()
      .add(R.id.fragment_container, fragment)
      .commitNow();
    
// Load the fragment with a Place ID.
fragment.loadWithPlaceId(placeId);
      
// Load the fragment with a resource name.
// fragment.loadWithResourceName(resourceName);

See complete code to load the Place Details widget

Kotlin

        import android.os.Bundle
        import android.util.Log
        import android.view.View
        import android.widget.FrameLayout
        import androidx.appcompat.app.AppCompatActivity
        import com.google.android.gms.maps.CameraUpdateFactory
        import com.google.android.gms.maps.GoogleMap
        import com.google.android.gms.maps.OnMapReadyCallback
        import com.google.android.gms.maps.SupportMapFragment
        import com.google.android.gms.maps.model.LatLng
        import com.google.android.gms.maps.model.PointOfInterest
        import com.google.android.libraries.places.api.Places
        import com.google.android.libraries.places.api.net.PlacesClient
        import com.google.android.libraries.places.widget.PlaceDetailsCompactFragment
        import com.google.android.libraries.places.widget.PlaceDetailsCompactFragment.Companion.ALL_CONTENT
        import com.google.android.libraries.places.widget.model.Orientation
        
        class MainActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnPoiClickListener {
            private var googleMap: GoogleMap? = null
            private val orientation: Orientation = Orientation.HORIZONTAL
            private lateinit var placesClient: PlacesClient
            private var placeDetailsFragment: PlaceDetailsCompactFragment? = null
        
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(R.layout.activity_main)
        
                // --- Initialize Places SDK ---
                val apiKey = BuildConfig.PLACES_API_KEY
                if (apiKey.isEmpty()) {
                    Log.e("Places test", "No api key")
                    finish()
                    return
                }
                Places.initializeWithNewPlacesApiEnabled(applicationContext, apiKey)
                placesClient = Places.createClient(this)
                // -----------------------------
        
                val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment?
                mapFragment?.getMapAsync(this)
            }
        
            override fun onMapReady(map: GoogleMap) {
                googleMap = map
                val sydney = LatLng(-33.8688, 151.2093)
                val zoomLevel = 13f
                googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, zoomLevel))
                googleMap?.setOnPoiClickListener(this)
            }
        
            override fun onPoiClick(poi: PointOfInterest) {
                val placeId = poi.placeId
                Log.d("POI Click", "Place ID: $placeId")
                showPlaceDetailsFragment(placeId)
            }
        
            private fun showPlaceDetailsFragment(placeId: String) {
                placeDetailsFragment = PlaceDetailsCompactFragment.newInstance(
                    ALL_CONTENT,
                    orientation,
                    R.style.CustomizedPlaceDetailsTheme,
                )
                supportFragmentManager
                    .beginTransaction()
                    .replace(findViewById<FrameLayout>(R.id.place_details_fragment_host).id, placeDetailsFragment!!)
                    .commitNow()
                placeDetailsFragment?.loadWithPlaceId(placeId)
            }
        }               
        
        

Customize place details

Places UI kit offers a design system approach to visual customization roughly based on Material Design (with some Google-Maps-specific modifications). See Material Design's reference for Color and Typography. By default, the style adheres to the Google Maps visual design language.

Place details customization options

When instantiating a fragment, you can specify a theme that overrides any of the default style attributes. Any theme attributes that are not overridden use the default styles. If you'd like to support a dark theme, you can add an entry for the color in values-night/colors.xml.

  <style name="CustomizedPlaceDetailsTheme" parent="PlacesMaterialsTheme">
    <item name="placesColorPrimary">@color/app_primary_color</item>
    <item name="placesColorOnSurface">@color/app_color_on_surface</item>
    <item name="placesColorOnSurfaceVariant">@color/app_color_on_surface</item>
  
    <item name="placesTextAppearanceBodySmall">@style/app_text_appearence_small</item>
  
    <item name="placesCornerRadius">20dp</item>
  </style>

You can customize the following styles:

Theme attribute Usage
Color
placesColorSurface Container and dialog background
placesColorOnSurface Headings, dialog content
placesColorOnSurfaceVariant Place information
placesColorPrimary Links
placesColorOutlineDecorative Container border
placesColorSecondaryContainer Button background
placesColorOnSecondaryContainer Button text and icon
placesColorPositive Place "Open" now label
placesColorNegative Place "Closed" now label
placesColorInfo Accessible entrance icon
   
Typography
placesTextAppearanceHeadlineMedium Dialog headings
placesTextAppearanceTitleSmall Place name
placesTextAppearanceBodyMedium Dialog content
placesTextAppearanceBodySmall Place information
placesTextAppearanceLabelLarge Button label
   
Corners
placesCornerRadius Container corners
   
Google Maps Brand Attribution
placesColorAttributionLight Light theme Google Maps attribution and disclosure button (enums for white, gray, and black)
placesColorAttributionDark Dark theme Google Maps attribution and disclosure button (enums for white, gray, and black)

Width and height

For vertical views, the recommended width is between 180dp and 300dp. For horizontal views, the recommended width is between 180dp and 500dp. View smaller than 160dp may not display correctly.

Best practice is to not set a height. This will allow the content in the window to set the height, allowing all the information to be displayed.

Attribution colors

Google Maps' terms of service require you to use one of three brand colors for the Google Maps attribution. This attribution must be visible and accessible when customization changes have been made.

We offer 3 brand colors to choose from that can be independently set for light and dark themes:

  • Light theme: placesColorAttributionLight with enums for white, gray, and black.
  • Dark theme: placesColorAttributionDark with enums for white, gray, and black.

Customization examples

This sample customizes the standard content.

  val fragmentStandardContent = PlaceDetailsCompactFragment.newInstance(
    orientation,
    PlaceDetailsCompactFragment.STANDARD_CONTENT,
    R.style.CustomizedPlaceDetailsTheme,
  )

This sample customizes all content.

  val fragmentAllContent = PlaceDetailsCompactFragment.newInstance(
    orientation,
    PlaceDetailsCompactFragment.ALL_CONTENT,
    R.style.CustomizedPlaceDetailsTheme,
  )