A composable component model — GeoMap provides the container, and everything else is composed as children.
BrownieJS uses a composable component model. GeoMap provides the map container with tile rendering. TileLayer, Marker, MarkerCluster, Popup, Circle, Route, and Geolocation are composed as children.
npm install @brownie-js/reactimport { GeoMap, TileLayer, Marker } from '@brownie-js/react';
function MyMap() {
return (
<div style={{ width: '100%', height: 400 }}>
<GeoMap center={[-46.63, -23.55]} zoom={10} mapLabel="My map">
<TileLayer />
<Marker coordinates={[-46.63, -23.55]} ariaLabel="Sao Paulo" />
</GeoMap>
</div>
);
}GeoMap provides the map container and context. TileLayer renders OSM tiles. Marker, Route, and Geolocation are composed as children.
BrownieJS uses [longitude, latitude] order — the GeoJSON standard — for all coordinate props (center, coordinates, bounds). This is the opposite of Leaflet, which uses [lat, lng].
// Leaflet (lat, lng):
center={[-23.55, -46.63]}
// BrownieJS (lon, lat) — GeoJSON:
center={[-46.63, -23.55]}Migrating from Leaflet? Flip your coordinates: Leaflet's [lat, lng] becomes [lng, lat] in BrownieJS.
The root map container component. Provides a tile-based map with configurable center and zoom, auto-sizing via ResizeObserver, zoom and pan navigation, and context for all child components. Exposes an imperative handle via ref with flyTo(), fitBounds(), getZoom(), getCenter(), and getBounds().
import { GeoMap, TileLayer, Marker } from '@brownie-js/react';
function InteractiveMap() {
return (
<div style={{ width: '100%', height: 500 }}>
<GeoMap
center={[-46.63, -23.55]}
zoom={10}
minZoom={3}
maxZoom={18}
onZoomChange={(zoom) => console.log('Zoom:', zoom)}
mapLabel="Interactive map"
>
<TileLayer />
<Marker coordinates={[-46.63, -23.55]} ariaLabel="Sao Paulo" />
</GeoMap>
</div>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| center | [number, number] | [0, 0] | Map center as [longitude, latitude]. |
| zoom | number | 2 | Initial zoom level. |
| children | ReactNode | — | Child components (TileLayer, Marker, Route, etc.). |
| className | string | — | CSS class name for the map container. |
| style | CSSProperties | — | CSS styles for the map container. |
| mapLabel | string | "Interactive map" | Accessible label for the map container. |
| minZoom | number | 1 | Minimum zoom level. |
| maxZoom | number | 19 | Maximum zoom level. |
| bounds | { sw: [number, number]; ne: [number, number] } | — | Initial bounds to fit the map to. |
| width | number | — | Fixed width in pixels (auto-sizes if omitted). |
| height | number | — | Fixed height in pixels (auto-sizes if omitted). |
| onClick | (event: { latlng: [number, number]; pixel: [number, number]; originalEvent: MouseEvent }) => void | — | Called when the map is clicked. |
| onZoomChange | (zoom: number) => void | — | Fires during zoom with current zoom level. |
| onMoveEnd | (state: { center: [number, number]; zoom: number; bounds: { sw: [number, number]; ne: [number, number] } }) => void | — | Fires when a zoom or pan interaction ends. |
| showAttribution | boolean | true | Show the tile attribution overlay. Default: true. |
| isLoading | boolean | false | When true, renders the loader placeholder instead of the map. Use while async data (markers, routes, etc.) is being fetched. |
| loader | ReactNode | <Loader /> | Custom loader element to render when isLoading is true. Defaults to the built-in <Loader /> component. |
| interactiveZoom | boolean | true | Enables zoom via scroll wheel, pinch gesture, and double-click. Set to false to lock the zoom level while still allowing pan. Default: true. |
| onError | (error: Error, info: React.ErrorInfo) => void | — | Called when an error is thrown inside the map. Receives (error: Error, info: React.ErrorInfo). Use to connect error monitoring services like Sentry or Datadog. |
GeoMap accepts a ref that exposes methods for programmatic control — useful when you need to navigate the map from outside the component tree (e.g. a "use my location" button).
import { useRef } from 'react';
import { GeoMap, TileLayer, GeoMapHandle } from '@brownie-js/react';
function MapWithControls() {
const mapRef = useRef<GeoMapHandle>(null);
return (
<div style={{ width: '100%', height: 500 }}>
<GeoMap ref={mapRef} center={[-46.63, -23.55]} zoom={10} mapLabel="Map">
<TileLayer />
</GeoMap>
<button onClick={() => mapRef.current?.flyTo([-43.17, -22.91], 12)}>
Rio de Janeiro
</button>
<button onClick={() =>
mapRef.current?.flyTo({ center: [-46.63, -23.55], zoom: 14, duration: 600 })
}>
São Paulo (slow)
</button>
<button onClick={() =>
mapRef.current?.fitBounds({ sw: [-46.8, -23.7], ne: [-46.4, -23.4] })
}>
Fit region
</button>
</div>
);
}flyTo(options: FlyToOptions): void
flyTo(center: [number, number], zoom?: number): void
fitBounds(bounds: { sw: [number, number]; ne: [number, number] }, padding?: number): void
getZoom(): number
getCenter(): [number, number]
getBounds(): { sw: [number, number]; ne: [number, number] }flyTo() animates to the target position using RequestAnimationFrame. Accepts an optional duration (default 300ms) and easing function. Respects prefers-reduced-motion: if the user has reduced motion enabled, the map jumps instantly instead of animating.
Renders a tile grid from a URL template (e.g., OpenStreetMap). Must be placed inside GeoMap.
import { GeoMap, TileLayer } from '@brownie-js/react';
function MapWithTiles() {
return (
<div style={{ width: '100%', height: 400 }}>
<GeoMap center={[-46.63, -23.55]} zoom={10} mapLabel="Tile map">
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
</GeoMap>
</div>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| url | string | "https://tile.openstreetmap.org/{z}/{x}/{y}.png" | Tile URL template with {x}, {y}, {z} placeholders. |
| opacity | number | 1 | Layer opacity (0–1). |
| zIndex | number | — | CSS z-index for layer ordering. |
Renders a marker at a geographic coordinate. Supports custom SVG children, drag-and-drop, click handlers, and tooltips.
import { GeoMap, TileLayer, Marker } from '@brownie-js/react';
function MapWithMarkers() {
return (
<GeoMap center={[-43.17, -22.91]} zoom={12} mapLabel="Map with markers">
<TileLayer />
<Marker
coordinates={[-43.17, -22.91]}
color="#d4850c"
size={10}
onClick={(event, data) => console.log('Clicked marker')}
ariaLabel="Rio de Janeiro"
/>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| coordinates | [number, number] | — | Geographic coordinates [longitude, latitude] (GeoJSON convention). |
| color | string | '#d4850c' | Marker fill color. |
| size | number | 8 | Marker diameter in pixels. |
| icon | ReactNode | — | Custom ReactNode to replace the default marker icon. |
| anchor | "center" | "bottom" | "center" | Anchor point of the marker. |
| draggable | boolean | false | Whether marker can be dragged. |
| opacity | number | — | Marker opacity (0–1). |
| children | ReactNode | — | Custom SVG content. Replaces default circle when provided. |
| onClick | (event: MouseEvent, data?: Record<string, unknown>) => void | — | Called when marker is clicked. |
| onMouseEnter | (event: MouseEvent) => void | — | Called when mouse enters marker. |
| onMouseLeave | (event: MouseEvent) => void | — | Called when mouse leaves marker. |
| onDragEnd | (coordinates: [number, number], data?: Record<string, unknown>) => void | — | Called when drag completes with new geographic coordinates. |
| data | Record<string, unknown> | — | Arbitrary data to associate with the marker. |
| animated | boolean | false | Enable enter animation (fade-in + slide) when the marker mounts. |
| ariaLabel | string | — | Accessible name for the marker. |
Groups nearby Marker children into clusters using a grid-based algorithm. Automatically re-clusters on zoom changes.
import { GeoMap, TileLayer, Marker } from '@brownie-js/react';
import { MarkerCluster } from '@brownie-js/react/cluster';
function ClusteredMap() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Clustered markers">
<TileLayer />
<MarkerCluster radius={60} maxZoom={16}>
<Marker coordinates={[-46.63, -23.55]} ariaLabel="Point A" />
<Marker coordinates={[-46.64, -23.56]} ariaLabel="Point B" />
<Marker coordinates={[-46.62, -23.54]} ariaLabel="Point C" />
</MarkerCluster>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| radius | number | 60 | Cluster grid cell size in pixels. |
| maxZoom | number | 16 | Zoom level above which markers are not clustered. |
| renderCluster | (cluster: ClusterData) => ReactNode | — | Custom render function for cluster markers. |
| onClick | (cluster: ClusterData) => void | — | Called when a cluster is clicked. |
| animated | boolean | false | Enable smooth transition animations when clusters merge or split. |
| categoryKey | string | — | Data key used to group markers into categories within clusters. |
| categoryColors | Record<string, string> | — | Map of category values to colors for multi-category cluster rendering. |
| children | ReactNode | — | Marker components to cluster. |
An HTML overlay positioned at geographic coordinates. Can be used standalone or as a child of Marker.
import { GeoMap, TileLayer, Marker, Popup } from '@brownie-js/react';
import { useState } from 'react';
function MapWithPopup() {
const [selected, setSelected] = useState(false);
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with popup">
<TileLayer />
<Marker
coordinates={[-46.63, -23.55]}
onClick={() => setSelected(true)}
ariaLabel="Sao Paulo"
>
{selected && (
<Popup offset={[0, -10]} onClose={() => setSelected(false)}>
<div>Hello from Sao Paulo!</div>
</Popup>
)}
</Marker>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| coordinates | [number, number] | — | Geographic position [longitude, latitude]. Inherited from parent Marker if omitted. |
| offset | [number, number] | — | Pixel offset [x, y] from the anchor position. |
| closeOnClick | boolean | — | Whether clicking the map closes the popup. |
| onClose | () => void | — | Called when the popup is closed. |
| className | string | — | CSS class for the popup container. |
| style | CSSProperties | — | Inline styles for the popup container. |
| image | { src: string; alt: string; height?: number } | — | Optional hero image displayed above the popup content. |
| children | ReactNode | — | Popup content. |
Renders an SVG circle on the map with a geographic center and radius in meters.
import { GeoMap, TileLayer, Circle } from '@brownie-js/react';
function MapWithCircle() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={13} mapLabel="Map with circle">
<TileLayer />
<Circle
center={[-46.63, -23.55]}
radius={2000}
color="#7c8b6f"
fillColor="rgba(124,139,111,0.15)"
ariaLabel="Search area"
/>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| center | [number, number] | — | Center coordinates [longitude, latitude]. |
| radius | number | — | Radius in meters. |
| color | string | — | Stroke color. |
| fillColor | string | — | Fill color. |
| strokeWidth | number | — | Stroke width in pixels. |
| dashArray | string | — | SVG stroke-dasharray for dashed borders. |
| opacity | number | — | Overall opacity (0–1). |
| onClick | (event: MouseEvent) => void | — | Called when the circle is clicked. |
| ariaLabel | string | — | Accessible name for the circle. |
A lightweight overlay that displays content at a pixel position. Typically used with mouse events on markers or routes.
import { GeoMap, TileLayer, Marker, Tooltip } from '@brownie-js/react';
import { useState } from 'react';
function MapWithTooltip() {
const [tip, setTip] = useState<{ x: number; y: number } | null>(null);
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with tooltip">
<TileLayer />
<Marker
coordinates={[-46.63, -23.55]}
onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY })}
onMouseLeave={() => setTip(null)}
ariaLabel="Sao Paulo"
/>
{tip && <Tooltip x={tip.x} y={tip.y} content="Sao Paulo" />}
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| x | number | — | Horizontal pixel position. |
| y | number | — | Vertical pixel position. |
| content | ReactNode | — | Tooltip content. |
| className | string | — | CSS class for the tooltip container. |
| style | CSSProperties | — | Inline styles for the tooltip container. |
Draws an SVG path along a series of geographic coordinates. Supports custom stroke styling, dashed lines, OSRM routing integration, and tooltips.
import { GeoMap, TileLayer } from '@brownie-js/react';
import { Route } from '@brownie-js/react/route';
function MapWithRoute() {
const waypoints: [number, number][] = [
[-43.17, -22.91], // Rio de Janeiro
[-46.63, -23.55], // Sao Paulo
];
return (
<GeoMap center={[-44.9, -23.2]} zoom={8} mapLabel="Route map">
<TileLayer />
<Route
coordinates={waypoints}
color="#d4850c"
strokeWidth={3}
routing={true}
onRouteLoaded={(data) => console.log(`${data.distance}m`)}
/>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| coordinates | [number, number][] | — | Array of geographic coordinates [longitude, latitude] defining the route. |
| color | string | '#d4850c' | Stroke color. |
| strokeWidth | number | 2 | Stroke width in pixels. |
| dashArray | string | — | SVG stroke-dasharray for dashed lines (e.g. "5,5"). |
| routing | boolean | false | Enable OSRM routing. |
| routingUrl | string | — | Custom OSRM endpoint URL. |
| onClick | (event: MouseEvent) => void | — | Called when the route path is clicked. |
| onMouseEnter | (event: MouseEvent) => void | — | Called when mouse enters the route path. |
| onMouseLeave | (event: MouseEvent) => void | — | Called when mouse leaves the route path. |
| onRouteLoaded | (data: { distance: number; duration: number; geometry: [number, number][] }) => void | — | Called when OSRM route data loads. |
| animated | boolean | false | Enable ant trail animation along the route path. |
| animationSpeed | number | 2 | Duration of one animation cycle in seconds. |
| ariaLabel | string | — | Accessible name for the route. |
Accesses the browser Geolocation API to track the user's position. Can continuously watch position changes with configurable accuracy and timeout.
import { GeoMap, TileLayer } from '@brownie-js/react';
import { Geolocation } from '@brownie-js/react/geo';
function LiveLocationMap() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Live location map">
<TileLayer />
<Geolocation
watch={true}
enableHighAccuracy={true}
onError={(err) => console.warn(err.message)}
/>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| watch | boolean | true | Whether to continuously watch position. |
| enableHighAccuracy | boolean | true | Enable high accuracy mode. |
| timeout | number | 10000 | Timeout in milliseconds. |
| maximumAge | number | 0 | Maximum age of cached position in milliseconds. |
| onError | (error: GeolocationPositionError) => void | — | Called when a geolocation error occurs. |
Positions child controls in a corner of the map. Use with built-in controls (ZoomControl, ScaleBar) or any custom content.
import { GeoMap, TileLayer, MapControl } from '@brownie-js/react';
import { ZoomControl, ScaleBar } from '@brownie-js/react/controls';
function MapWithControls() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with controls">
<TileLayer />
<MapControl position="top-right">
<ZoomControl />
</MapControl>
<MapControl position="bottom-left">
<ScaleBar />
</MapControl>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| position | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'top-right' | Corner position: 'top-left', 'top-right', 'bottom-left', or 'bottom-right'. |
| children | ReactNode | — | Control content to render in the map corner. |
| className | string | — | CSS class for the control container. |
| style | CSSProperties | — | Inline styles for the control container. |
A custom SVG overlay layer. Provides a project() render prop that converts geographic coordinates to pixel positions, allowing you to draw arbitrary SVG shapes on the map.
import { GeoMap, TileLayer, SVGLayer } from '@brownie-js/react';
function MapWithSVGOverlay() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with SVG layer">
<TileLayer />
<SVGLayer>
{({ project }) => {
const [x, y] = project(-46.63, -23.55);
return <circle cx={x} cy={y} r={20} fill="rgba(255,0,0,0.3)" />;
}}
</SVGLayer>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| children | (ctx: { project }) => ReactNode | — | Render function receiving { project } for coordinate-to-pixel conversion. |
| className | string | — | CSS class for the SVG container. |
| style | CSSProperties | — | Inline styles for the SVG container. |
A custom HTML overlay layer. Provides a project() render prop that converts geographic coordinates to pixel positions, allowing you to render arbitrary HTML elements on the map.
import { GeoMap, TileLayer, HTMLLayer } from '@brownie-js/react';
function MapWithHTMLOverlay() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with HTML layer">
<TileLayer />
<HTMLLayer>
{({ project }) => {
const [x, y] = project(-46.63, -23.55);
return (
<div style={{ position: 'absolute', left: x, top: y, transform: 'translate(-50%, -50%)' }}>
Custom HTML content
</div>
);
}}
</HTMLLayer>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| children | (ctx: { project }) => ReactNode | — | Render function receiving { project } for coordinate-to-pixel conversion. |
| className | string | — | CSS class for the HTML container. |
| style | CSSProperties | — | Inline styles for the HTML container. |
A standalone map placeholder component rendered while async data loads. Used automatically by GeoMap when isLoading is true, and can also be used independently — for example, before a lazy-loaded map component mounts.
import { GeoMap, TileLayer, Loader } from '@brownie-js/react';
import { useState, useEffect } from 'react';
function MapWithLoader() {
const [markers, setMarkers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchMarkers().then((data) => {
setMarkers(data);
setIsLoading(false);
});
}, []);
return (
<div style={{ width: '100%', height: 400 }}>
<GeoMap center={[-46.63, -23.55]} zoom={10} isLoading={isLoading}>
<TileLayer />
{markers.map((m) => (
<Marker key={m.id} coordinates={m.coordinates} />
))}
</GeoMap>
</div>
);
}
// Standalone usage (e.g., before a lazy-loaded map)
function MapSkeleton() {
return (
<div style={{ width: '100%', height: 400 }}>
<Loader ariaLabel="Loading map data..." />
</div>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| ariaLabel | string | "Loading map" | Accessible label for the loading region. Announced by screen readers. Default: "Loading map". |
| className | string | — | CSS class name applied to the loader container. |
| style | CSSProperties | — | Inline CSS styles applied to the loader container. Merged with default layout styles. |
Returns the map context including viewport state, projection functions, and the flyTo() method for programmatic navigation. Must be used inside GeoMap.
import { useMap } from '@brownie-js/react';
// Programmatic navigation
function NavigationButton() {
const { flyTo } = useMap();
return (
<button onClick={() => flyTo([-46.63, -23.55], 12)}>
Go to São Paulo
</button>
);
}
// With full options
function NavigationButtonAnimated() {
const { flyTo } = useMap();
return (
<button onClick={() => flyTo({ center: [-46.63, -23.55], zoom: 14, duration: 600 })}>
Fly (slow)
</button>
);
}
// Projection utilities
function CustomOverlay() {
const { center, zoom, project } = useMap();
const [x, y] = project(center[0], center[1]);
return <div style={{ position: 'absolute', left: x, top: y }}>Zoom: {zoom}</div>;
}Returns: MapContextValue with project(), invert(), flyTo(), center, zoom, width, height.
Wraps the browser Geolocation API. Returns the user's position, loading state, and errors. By default continuously watches via watchPosition().
import { useGeolocation } from '@brownie-js/react/geo';
function LocationInfo() {
const { position, loading, error } = useGeolocation({ watch: true });
if (loading) return <p>Locating...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!position) return null;
return <p>Lat: {position.latitude}, Lng: {position.longitude}</p>;
}Returns: { position: { latitude, longitude, accuracy } | null, error, loading }
Fetches road routing geometry from an OSRM-compatible API. Features in-memory caching and AbortController cleanup.
import { useOsrmRoute } from '@brownie-js/react/route';
function RouteInfo() {
const waypoints: [number, number][] = [
[-43.17, -22.91],
[-46.63, -23.55],
];
const { data, loading } = useOsrmRoute(waypoints, true);
if (loading) return <p>Calculating route...</p>;
if (!data) return null;
return <p>Distance: {(data.distance / 1000).toFixed(1)} km</p>;
}Signature: useOsrmRoute(waypoints, enabled, routingUrl?)
Returns: { data: { coordinates, distance, duration } | null, loading, error }
Calls the Nominatim (OpenStreetMap) reverse geocoding API to resolve coordinates into an address.
import { useReverseGeocode } from '@brownie-js/react/geo';
function AddressDisplay() {
const { data, loading } = useReverseGeocode(-23.55, -46.63);
if (loading) return <p>Looking up address...</p>;
if (!data) return null;
return <p>{data.displayName}</p>;
}Signature: useReverseGeocode(lat, lng)
Returns: { data: { road, suburb, city, state, country, postcode, displayName } | null, loading, error }
Headless hooks provide the logic and state for map components without rendering any UI. Use them to build fully custom components with your own markup and styling.
Manages popup positioning, auto-flip, and visibility state. Returns style and props to spread on your custom popup element.
import { usePopup } from '@brownie-js/react';
function CustomPopup({ coordinates, onClose }) {
const { style, isFlipped, props, popupRef } = usePopup({
coordinates,
offset: [0, -10],
onClose,
});
return (
<div ref={popupRef} style={style} {...props}>
<p>Custom popup content</p>
{isFlipped && <span>Flipped!</span>}
</div>
);
}Signature: usePopup(options)
Returns: { style, isVisible, isFlipped, close, props, popupRef }
Manages tooltip positioning relative to a pixel coordinate. Returns style and props for your custom tooltip element.
import { useTooltip } from '@brownie-js/react';
function CustomTooltip({ x, y, content }) {
const { style, props } = useTooltip({ x, y });
return (
<div style={style} {...props}>
{content}
</div>
);
}Signature: useTooltip(options)
Returns: { style, props }
Manages marker positioning, drag state, and viewport culling. Returns style, handlers, and state for your custom marker element.
import { useMarker } from '@brownie-js/react';
function CustomMarker({ coordinates }) {
const { style, isOutOfView, isDragging, handlers, props } = useMarker({
coordinates,
draggable: true,
});
if (isOutOfView) return null;
return (
<div style={style} {...handlers} {...props}>
{isDragging ? 'Dragging...' : 'My Marker'}
</div>
);
}Signature: useMarker(options)
Returns: { style, isOutOfView, isDragging, handlers, props }
Computes the pixel center and radius for a geographic circle. Returns SVG props and container style for your custom circle element.
import { useCircle } from '@brownie-js/react';
function CustomCircle({ center, radius }) {
const { center: pixelCenter, radiusPx, svgProps, containerStyle } = useCircle({
center,
radius,
});
return (
<svg style={containerStyle} {...svgProps}>
<circle cx={pixelCenter[0]} cy={pixelCenter[1]} r={radiusPx} fill="rgba(0,0,255,0.2)" />
</svg>
);
}Signature: useCircle(options)
Returns: { center, radiusPx, svgProps, containerStyle }
Computes the SVG path data for a route and optionally fetches OSRM routing. Returns path data and loading state for your custom route element.
import { useRouteLayer } from '@brownie-js/react/route';
function CustomRoute({ coordinates }) {
const { pathD, svgProps, containerStyle, isLoading } = useRouteLayer({
coordinates,
routing: true,
});
if (isLoading) return null;
return (
<svg style={containerStyle} {...svgProps}>
<path d={pathD} stroke="blue" strokeWidth={3} fill="none" />
</svg>
);
}Signature: useRouteLayer(options)
Returns: { pathD, svgProps, containerStyle, isLoading, routeData }
Tracks the user's GPS position and computes pixel coordinates for the dot and accuracy ring. Returns position data and state for your custom geolocation element.
import { useGeolocationDot } from '@brownie-js/react/geo';
function CustomGeolocation() {
const { dotCenter, accuracyRadiusPx, containerStyle, loading } = useGeolocationDot({
watch: true,
});
if (loading || !dotCenter) return null;
return (
<svg style={containerStyle}>
<circle cx={dotCenter[0]} cy={dotCenter[1]} r={accuracyRadiusPx} fill="rgba(0,100,255,0.15)" />
<circle cx={dotCenter[0]} cy={dotCenter[1]} r={6} fill="#0064ff" />
</svg>
);
}Signature: useGeolocationDot(options)
Returns: { position, dotCenter, accuracyRadiusPx, containerStyle, error, loading }
Provides projection functions and map dimensions for building custom layers. A convenience wrapper around useMap() optimized for layer rendering.
import { useMapLayer } from '@brownie-js/react';
function CustomLayer() {
const { project, width, height, zoom } = useMapLayer();
const [x, y] = project(-46.63, -23.55);
return (
<svg style={{ position: 'absolute', width, height, pointerEvents: 'none' }}>
<circle cx={x} cy={y} r={10} fill="red" />
<text x={x + 14} y={y + 4}>Zoom: {zoom}</text>
</svg>
);
}Signature: useMapLayer()
Returns: { project, invert, width, height, zoom, center }
BrownieJS's Circle component uses a geographic radius in meters — it scales with zoom. For a fixed pixel-size dot that stays the same size regardless of zoom (equivalent to Leaflet's CircleMarker), use useMapLayer with a plain SVG circle and a fixed pixel r:
import { useMapLayer } from '@brownie-js/react';
// Fixed pixel-size dot — does NOT scale with zoom (Leaflet's CircleMarker equivalent)
function ApproxLocationDot({ coordinates }: { coordinates: [number, number] }) {
const { project, width, height } = useMapLayer();
const [x, y] = project(coordinates[0], coordinates[1]);
return (
<svg style={{ position: 'absolute', width, height, pointerEvents: 'none' }}>
<circle cx={x} cy={y} r={10} fill="orange" opacity={0.7} />
</svg>
);
}
// For a geographic area that DOES scale with zoom, use <Circle radius={meters} /> instead.All BrownieJS components support visual customization via CSS custom properties (variables). You can set them globally on your map container or use MapThemeProvider for a React-friendly API.
Set any --bm-* variable on a parent element to theme all BrownieJS components within it. Available variables: --bm-popup-bg, --bm-popup-color, --bm-popup-radius, --bm-popup-shadow, --bm-tooltip-bg, --bm-tooltip-color, --bm-tooltip-border, --bm-tooltip-radius, --bm-tooltip-shadow, --bm-marker-color, --bm-circle-color, --bm-circle-fill, --bm-route-color, --bm-geolocation-color, --bm-attribution-bg, --bm-focus-ring, --bm-control-bg, --bm-control-color, --bm-control-shadow, --bm-control-radius, --bm-control-padding, --bm-control-gap.
/* Set CSS custom properties on any parent element */
.my-map {
--bm-popup-bg: #1a1a1a;
--bm-popup-color: #ffffff;
--bm-popup-radius: 12px;
--bm-tooltip-bg: #333;
--bm-tooltip-color: #fff;
--bm-marker-color: #e74c3c;
--bm-route-color: #3498db;
--bm-circle-color: #2ecc71;
--bm-focus-ring: #9b59b6;
--bm-control-bg: #1a1a1a;
--bm-control-color: #ffffff;
}A React component that converts a theme object into CSS custom properties. Import from @brownie-js/react/theme. Accepts camelCase keys that map to --bm-* variables (e.g. popupBg becomes --bm-popup-bg).
import { MapThemeProvider } from '@brownie-js/react/theme';
import { GeoMap, TileLayer, Marker, Popup } from '@brownie-js/react';
function DarkMap() {
return (
<MapThemeProvider
theme={{
popupBg: '#1a1a1a',
popupColor: '#fff',
popupRadius: '12px',
markerColor: '#e74c3c',
controlBg: '#1a1a1a',
controlColor: '#fff',
}}
>
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Dark themed map">
<TileLayer />
<Marker coordinates={[-46.63, -23.55]} ariaLabel="Sao Paulo" />
</GeoMap>
</MapThemeProvider>
);
}Ready-to-use map controls imported from @brownie-js/react/controls. Use them inside MapControl to position them on the map.
Provides zoom in (+) and zoom out (-) buttons with keyboard accessibility.
import { GeoMap, TileLayer, MapControl } from '@brownie-js/react';
import { ZoomControl } from '@brownie-js/react/controls';
function MapWithZoom() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with zoom control">
<TileLayer />
<MapControl position="top-right">
<ZoomControl />
</MapControl>
</GeoMap>
);
}Displays a distance scale bar that updates with the current zoom level. Supports metric and imperial units.
import { GeoMap, TileLayer, MapControl } from '@brownie-js/react';
import { ScaleBar } from '@brownie-js/react/controls';
function MapWithScale() {
return (
<GeoMap center={[-46.63, -23.55]} zoom={12} mapLabel="Map with scale bar">
<TileLayer />
<MapControl position="bottom-left">
<ScaleBar unit="metric" maxWidth={150} />
</MapControl>
</GeoMap>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| maxWidth | number | 100 | Maximum width of the scale bar in pixels. |
| unit | 'metric' | 'imperial' | 'metric' | Unit system: 'metric' or 'imperial'. |