or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

addons.mdadvanced.mdcore-components.mddrawing.mdhocs.mdindex.mdlayers.mdplaces.mdshapes.mdvisualization.md

places.mddocs/

0

# Places & Search

1

2

Google Places API integration components for location search, autocomplete functionality, and place details. These components provide search capabilities within map contexts.

3

4

## Capabilities

5

6

### SearchBox

7

8

Map-bound search box component that provides Google Places autocomplete functionality within a map context.

9

10

```javascript { .api }

11

/**

12

* Map-bound search box component with Google Places integration

13

*/

14

class SearchBox extends Component<SearchBoxProps> {

15

/** Returns the current search bounds */

16

getBounds(): google.maps.LatLngBounds;

17

/** Returns the array of selected places */

18

getPlaces(): google.maps.places.PlaceResult[];

19

}

20

21

interface SearchBoxProps {

22

/** Position of the control on the map */

23

controlPosition?: number;

24

/** Default bounds for biasing search results */

25

defaultBounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;

26

/** Controlled bounds for biasing search results */

27

bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;

28

/** Callback when places selection changes */

29

onPlacesChanged?(): void;

30

}

31

```

32

33

**Usage Example:**

34

35

```javascript

36

import SearchBox from "react-google-maps/lib/components/places/SearchBox";

37

38

const MapWithSearch = () => {

39

const [searchBox, setSearchBox] = useState(null);

40

const [markers, setMarkers] = useState([]);

41

42

const onPlacesChanged = () => {

43

const places = searchBox.getPlaces();

44

45

// Clear existing markers

46

setMarkers([]);

47

48

if (places.length === 0) {

49

return;

50

}

51

52

// Create markers for each place

53

const newMarkers = places.map(place => ({

54

position: {

55

lat: place.geometry.location.lat(),

56

lng: place.geometry.location.lng()

57

},

58

title: place.name,

59

place: place

60

}));

61

62

setMarkers(newMarkers);

63

64

// Fit map bounds to show all places

65

const bounds = new google.maps.LatLngBounds();

66

places.forEach(place => {

67

if (place.geometry.viewport) {

68

bounds.union(place.geometry.viewport);

69

} else {

70

bounds.extend(place.geometry.location);

71

}

72

});

73

// map.fitBounds(bounds);

74

};

75

76

return (

77

<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>

78

<SearchBox

79

ref={ref => setSearchBox(ref)}

80

bounds={new google.maps.LatLngBounds(

81

new google.maps.LatLng(37.7049, -122.4794),

82

new google.maps.LatLng(37.8449, -122.3594)

83

)}

84

controlPosition={google.maps.ControlPosition.TOP_LEFT}

85

onPlacesChanged={onPlacesChanged}

86

>

87

<input

88

type="text"

89

placeholder="Search for places..."

90

style={{

91

boxSizing: 'border-box',

92

border: '1px solid transparent',

93

width: '240px',

94

height: '32px',

95

marginTop: '27px',

96

padding: '0 12px',

97

borderRadius: '3px',

98

boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)',

99

fontSize: '14px',

100

outline: 'none',

101

textOverflow: 'ellipsis',

102

}}

103

/>

104

</SearchBox>

105

106

{markers.map((marker, index) => (

107

<Marker

108

key={index}

109

position={marker.position}

110

title={marker.title}

111

/>

112

))}

113

</GoogleMap>

114

);

115

};

116

```

117

118

### StandaloneSearchBox

119

120

Standalone search box component that works independently of a map context, useful for search forms and location pickers.

121

122

```javascript { .api }

123

/**

124

* Standalone search box component independent of map context

125

*/

126

class StandaloneSearchBox extends Component<StandaloneSearchBoxProps> {

127

/** Returns the current search bounds */

128

getBounds(): google.maps.LatLngBounds;

129

/** Returns the array of selected places */

130

getPlaces(): google.maps.places.PlaceResult[];

131

}

132

133

interface StandaloneSearchBoxProps {

134

/** Default bounds for biasing search results */

135

defaultBounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;

136

/** Controlled bounds for biasing search results */

137

bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;

138

/** Callback when places selection changes */

139

onPlacesChanged?(): void;

140

}

141

```

142

143

**Usage Example:**

144

145

```javascript

146

import StandaloneSearchBox from "react-google-maps/lib/components/places/StandaloneSearchBox";

147

148

const LocationPicker = ({ onLocationSelect }) => {

149

const [searchBox, setSearchBox] = useState(null);

150

const [selectedPlace, setSelectedPlace] = useState(null);

151

152

const onPlacesChanged = () => {

153

const places = searchBox.getPlaces();

154

155

if (places.length > 0) {

156

const place = places[0];

157

const location = {

158

lat: place.geometry.location.lat(),

159

lng: place.geometry.location.lng(),

160

name: place.name,

161

address: place.formatted_address,

162

placeId: place.place_id,

163

types: place.types

164

};

165

166

setSelectedPlace(location);

167

if (onLocationSelect) {

168

onLocationSelect(location);

169

}

170

}

171

};

172

173

return (

174

<div style={{ padding: '20px', maxWidth: '400px' }}>

175

<h3>Select a Location</h3>

176

177

<StandaloneSearchBox

178

ref={ref => setSearchBox(ref)}

179

bounds={new google.maps.LatLngBounds(

180

new google.maps.LatLng(37.7049, -122.4794),

181

new google.maps.LatLng(37.8449, -122.3594)

182

)}

183

onPlacesChanged={onPlacesChanged}

184

>

185

<input

186

type="text"

187

placeholder="Search for a location..."

188

style={{

189

width: '100%',

190

padding: '12px',

191

fontSize: '16px',

192

border: '1px solid #ddd',

193

borderRadius: '4px',

194

outline: 'none'

195

}}

196

/>

197

</StandaloneSearchBox>

198

199

{selectedPlace && (

200

<div style={{

201

marginTop: '16px',

202

padding: '12px',

203

backgroundColor: '#f5f5f5',

204

borderRadius: '4px'

205

}}>

206

<h4>{selectedPlace.name}</h4>

207

<p>{selectedPlace.address}</p>

208

<p>

209

<strong>Coordinates:</strong> {selectedPlace.lat.toFixed(6)}, {selectedPlace.lng.toFixed(6)}

210

</p>

211

<p>

212

<strong>Types:</strong> {selectedPlace.types.join(', ')}

213

</p>

214

</div>

215

)}

216

</div>

217

);

218

};

219

```

220

221

## Google Places API Setup

222

223

### API Requirements

224

225

Places components require the Google Places API to be enabled and the places library to be loaded:

226

227

```javascript

228

const googleMapURL = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&libraries=places`;

229

230

const MapComponent = withScriptjs(withGoogleMap(() => (

231

<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>

232

<SearchBox>

233

<input type="text" placeholder="Search..." />

234

</SearchBox>

235

</GoogleMap>

236

)));

237

238

<MapComponent

239

googleMapURL={googleMapURL}

240

loadingElement={<div style={{ height: "100%" }} />}

241

containerElement={<div style={{ height: "400px" }} />}

242

mapElement={<div style={{ height: "100%" }} />}

243

/>

244

```

245

246

## Advanced Places Patterns

247

248

### Search with Custom Filters

249

250

Filter search results by place types:

251

252

```javascript

253

const RestaurantSearchBox = () => {

254

const [searchBox, setSearchBox] = useState(null);

255

const [places, setPlaces] = useState([]);

256

257

const onPlacesChanged = () => {

258

const allPlaces = searchBox.getPlaces();

259

260

// Filter for restaurants only

261

const restaurants = allPlaces.filter(place =>

262

place.types.includes('restaurant') ||

263

place.types.includes('food') ||

264

place.types.includes('meal_takeaway')

265

);

266

267

setPlaces(restaurants);

268

};

269

270

return (

271

<div>

272

<StandaloneSearchBox

273

ref={ref => setSearchBox(ref)}

274

onPlacesChanged={onPlacesChanged}

275

>

276

<input

277

type="text"

278

placeholder="Search for restaurants..."

279

style={{ width: '300px', padding: '8px' }}

280

/>

281

</StandaloneSearchBox>

282

283

<div style={{ marginTop: '16px' }}>

284

{places.map((place, index) => (

285

<div key={index} style={{ marginBottom: '12px', padding: '8px', border: '1px solid #ddd' }}>

286

<h4>{place.name}</h4>

287

<p>{place.formatted_address}</p>

288

<p>Rating: {place.rating || 'No rating'}</p>

289

<p>Types: {place.types.join(', ')}</p>

290

</div>

291

))}

292

</div>

293

</div>

294

);

295

};

296

```

297

298

### Search with Geolocation Bias

299

300

Bias search results based on user's current location:

301

302

```javascript

303

const LocationBiasedSearch = () => {

304

const [searchBox, setSearchBox] = useState(null);

305

const [userLocation, setUserLocation] = useState(null);

306

const [searchBounds, setSearchBounds] = useState(null);

307

308

useEffect(() => {

309

// Get user's current location

310

if (navigator.geolocation) {

311

navigator.geolocation.getCurrentPosition(

312

(position) => {

313

const userPos = {

314

lat: position.coords.latitude,

315

lng: position.coords.longitude

316

};

317

setUserLocation(userPos);

318

319

// Create search bounds around user location (5km radius)

320

const bounds = new google.maps.LatLngBounds();

321

const center = new google.maps.LatLng(userPos.lat, userPos.lng);

322

const radius = 0.045; // Approximately 5km

323

324

bounds.extend(new google.maps.LatLng(

325

userPos.lat + radius,

326

userPos.lng + radius

327

));

328

bounds.extend(new google.maps.LatLng(

329

userPos.lat - radius,

330

userPos.lng - radius

331

));

332

333

setSearchBounds(bounds);

334

},

335

(error) => {

336

console.error("Geolocation error:", error);

337

}

338

);

339

}

340

}, []);

341

342

return (

343

<StandaloneSearchBox

344

ref={ref => setSearchBox(ref)}

345

bounds={searchBounds}

346

onPlacesChanged={() => {

347

const places = searchBox.getPlaces();

348

console.log("Places near you:", places);

349

}}

350

>

351

<input

352

type="text"

353

placeholder={userLocation ? "Search near your location..." : "Search..."}

354

style={{ width: '300px', padding: '8px' }}

355

/>

356

</StandaloneSearchBox>

357

);

358

};

359

```

360

361

### Autocomplete with Place Details

362

363

Get detailed place information using the Places API:

364

365

```javascript

366

const DetailedPlaceSearch = () => {

367

const [searchBox, setSearchBox] = useState(null);

368

const [placeDetails, setPlaceDetails] = useState(null);

369

370

const onPlacesChanged = () => {

371

const places = searchBox.getPlaces();

372

373

if (places.length > 0) {

374

const place = places[0];

375

376

// Get additional place details

377

const service = new google.maps.places.PlacesService(

378

document.createElement('div')

379

);

380

381

service.getDetails({

382

placeId: place.place_id,

383

fields: [

384

'name', 'formatted_address', 'geometry', 'rating',

385

'photos', 'opening_hours', 'formatted_phone_number',

386

'website', 'reviews', 'price_level'

387

]

388

}, (detailedPlace, status) => {

389

if (status === google.maps.places.PlacesServiceStatus.OK) {

390

setPlaceDetails(detailedPlace);

391

}

392

});

393

}

394

};

395

396

return (

397

<div>

398

<StandaloneSearchBox

399

ref={ref => setSearchBox(ref)}

400

onPlacesChanged={onPlacesChanged}

401

>

402

<input

403

type="text"

404

placeholder="Search for detailed place info..."

405

style={{ width: '400px', padding: '12px' }}

406

/>

407

</StandaloneSearchBox>

408

409

{placeDetails && (

410

<div style={{ marginTop: '20px', padding: '16px', border: '1px solid #ddd' }}>

411

<h2>{placeDetails.name}</h2>

412

<p><strong>Address:</strong> {placeDetails.formatted_address}</p>

413

<p><strong>Rating:</strong> {placeDetails.rating}/5</p>

414

<p><strong>Phone:</strong> {placeDetails.formatted_phone_number}</p>

415

{placeDetails.website && (

416

<p><strong>Website:</strong> <a href={placeDetails.website} target="_blank" rel="noopener noreferrer">{placeDetails.website}</a></p>

417

)}

418

{placeDetails.opening_hours && (

419

<div>

420

<strong>Hours:</strong>

421

<ul>

422

{placeDetails.opening_hours.weekday_text.map((day, index) => (

423

<li key={index}>{day}</li>

424

))}

425

</ul>

426

</div>

427

)}

428

</div>

429

)}

430

</div>

431

);

432

};

433

```