or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-features.mdchild-components.mdgeographic-utilities.mdindex.mdmap-component.mdtile-system.md
tile.json

child-components.mddocs/

Child Components

React components rendered as children of GoogleMapReact are automatically positioned on the map using lat/lng coordinates. The component provides an internal hover system and passes special props to child components.

Capabilities

Child Component Props

Required and automatic props for components rendered on the map.

/**
 * Props interface for components rendered as children of GoogleMapReact
 */
interface MapChildProps {
  // Required positioning props
  lat: number;
  lng: number;
  
  // Automatically injected props
  $hover?: boolean;
  
  // Custom props (any additional props you want to pass)
  [key: string]: any;
}

Basic Usage:

// Simple marker component
const Marker = ({ text, $hover }) => (
  <div style={{
    backgroundColor: $hover ? 'red' : 'blue',
    color: 'white',
    padding: '4px 8px',
    borderRadius: '4px',
    transform: 'translate(-50%, -50%)' // Center the marker
  }}>
    {text}
  </div>
);

// Use in map
<GoogleMapReact
  defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
  defaultZoom={10}
>
  <Marker
    lat={37.7749}
    lng={-122.4194}
    text="San Francisco"
  />
</GoogleMapReact>

Hover System

GoogleMapReact includes an internal hover detection system that automatically manages hover states for child components.

interface HoverSystemProps {
  // Distance function for hover detection
  distanceToMouse?: (
    pt: { x: number; y: number },
    mousePos: { x: number; y: number },
    markerProps: any
  ) => number;
  
  // Maximum distance for hover detection (pixels)
  hoverDistance?: number;
  
  // Whether to debounce hover calculations
  debounced?: boolean;
}

Advanced Hover Example:

const InteractiveMarker = ({ text, $hover, onClick }) => (
  <div
    style={{
      backgroundColor: $hover ? '#ff4444' : '#4444ff',
      color: 'white',
      padding: '8px 12px',
      borderRadius: '8px',
      cursor: 'pointer',
      transform: 'translate(-50%, -50%)',
      transition: 'all 0.2s ease',
      boxShadow: $hover ? '0 4px 8px rgba(0,0,0,0.3)' : '0 2px 4px rgba(0,0,0,0.2)',
      fontSize: $hover ? '14px' : '12px'
    }}
    onClick={onClick}
  >
    {text}
  </div>
);

<GoogleMapReact
  defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
  defaultZoom={10}
  hoverDistance={20}
  debounced={true}
  onChildClick={(childKey, childProps) => {
    console.log('Marker clicked:', childProps.text);
  }}
>
  <InteractiveMarker
    key="sf-marker"
    lat={37.7749}
    lng={-122.4194}
    text="Click me!"
    onClick={() => alert('Marker clicked!')}
  />
</GoogleMapReact>

Positioning and Styling

Guidelines for properly positioning child components on the map.

interface PositioningStyles {
  position?: 'absolute' | 'relative';
  transform?: string;
  transformOrigin?: string;
  left?: string | number;
  top?: string | number;
}

Positioning Examples:

// Centered marker (most common)
const CenteredMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(-50%, -50%)',
    transformOrigin: 'center center'
  }}>
    {children}
  </div>
);

// Bottom-centered marker (pin style)
const PinMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(-50%, -100%)',
    transformOrigin: 'center bottom'
  }}>
    {children}
  </div>
);

// Top-left positioned marker
const TopLeftMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(0, 0)',
    transformOrigin: 'top left'
  }}>
    {children}
  </div>
);

// Usage
<GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
  <CenteredMarker lat={37.7749} lng={-122.4194}>
    <div style={{ backgroundColor: 'red', width: 20, height: 20, borderRadius: '50%' }} />
  </CenteredMarker>
  
  <PinMarker lat={37.7849} lng={-122.4094}>
    <div style={{ backgroundColor: 'blue', width: 0, height: 0, borderLeft: '10px solid transparent', borderRight: '10px solid transparent', borderTop: '20px solid blue' }} />
  </PinMarker>
</GoogleMapReact>

Advanced Patterns

Dynamic Marker Creation

Create markers dynamically from data arrays.

function DynamicMarkers({ locations }) {
  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
    >
      {locations.map((location, index) => (
        <Marker
          key={location.id || index}
          lat={location.lat}
          lng={location.lng}
          text={location.name}
          type={location.type}
        />
      ))}
    </GoogleMapReact>
  );
}

// Usage
const locations = [
  { id: 1, lat: 37.7749, lng: -122.4194, name: 'San Francisco', type: 'city' },
  { id: 2, lat: 37.7849, lng: -122.4094, name: 'North Beach', type: 'neighborhood' },
  { id: 3, lat: 37.7649, lng: -122.4294, name: 'Mission', type: 'neighborhood' }
];

<DynamicMarkers locations={locations} />

Conditional Rendering

Show/hide markers based on zoom level or other conditions.

function ZoomDependentMarkers({ zoom, markers }) {
  return (
    <GoogleMapReact
      zoom={zoom}
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      onChange={({ zoom }) => setZoom(zoom)}
    >
      {markers.map(marker => {
        // Only show detailed markers at high zoom levels
        if (marker.type === 'detailed' && zoom < 12) {
          return null;
        }
        
        // Only show overview markers at low zoom levels
        if (marker.type === 'overview' && zoom > 8) {
          return null;
        }
        
        return (
          <Marker
            key={marker.id}
            lat={marker.lat}
            lng={marker.lng}
            text={marker.name}
          />
        );
      })}
    </GoogleMapReact>
  );
}

Custom Hover Behavior

Implement custom hover detection logic.

function CustomHoverMap() {
  const customDistanceFunction = (pt, mousePos, markerProps) => {
    // Custom distance calculation - larger hover area for important markers
    const baseDistance = Math.sqrt(
      Math.pow(pt.x - mousePos.x, 2) + Math.pow(pt.y - mousePos.y, 2)
    );
    
    // Increase hover distance for VIP markers
    return markerProps.isVIP ? baseDistance * 0.5 : baseDistance;
  };

  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
      distanceToMouse={customDistanceFunction}
      hoverDistance={30}
    >
      <Marker lat={37.7749} lng={-122.4194} text="VIP Location" isVIP={true} />
      <Marker lat={37.7849} lng={-122.4094} text="Regular Location" isVIP={false} />
    </GoogleMapReact>
  );
}

Event Handling

Handle various mouse events on child components.

function EventHandlingMap() {
  const handleChildMouseEnter = (childKey, childProps) => {
    console.log('Mouse entered:', childProps.text);
  };

  const handleChildMouseLeave = (childKey, childProps) => {
    console.log('Mouse left:', childProps.text);
  };

  const handleChildClick = (childKey, childProps) => {
    console.log('Clicked:', childProps.text);
  };

  const handleChildMouseDown = (childKey, childProps) => {
    console.log('Mouse down:', childProps.text);
  };

  const handleChildMouseUp = (childKey, childProps) => {
    console.log('Mouse up:', childProps.text);
  };

  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
      onChildMouseEnter={handleChildMouseEnter}
      onChildMouseLeave={handleChildMouseLeave}
      onChildClick={handleChildClick}
      onChildMouseDown={handleChildMouseDown}
      onChildMouseUp={handleChildMouseUp}
    >
      <InteractiveMarker
        lat={37.7749}
        lng={-122.4194}
        text="Interactive Marker"
      />
    </GoogleMapReact>
  );
}

Performance Considerations

Minimize Re-renders

Use React.memo and stable keys to optimize performance with many markers.

const Marker = React.memo(({ lat, lng, text, $hover }) => (
  <div style={{
    backgroundColor: $hover ? 'red' : 'blue',
    color: 'white',
    padding: '4px 8px',
    borderRadius: '4px',
    transform: 'translate(-50%, -50%)'
  }}>
    {text}
  </div>
));

// Use stable keys and avoid inline object creation
function OptimizedMarkers({ locations }) {
  return (
    <GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
      {locations.map(location => (
        <Marker
          key={location.id} // Stable key
          lat={location.lat}
          lng={location.lng}
          text={location.name}
        />
      ))}
    </GoogleMapReact>
  );
}