@htmlbricks/hb-map
v0.76.5
Published
Interactive map: `center`, `zoom`, `source` (OSM or CARTO vector styles), `options` (e.g. `centerFromGeometries`, marker text layout), and `data` with markers (lng/lat, icon, popup HTML, text). CARTO vector uses `source.style` in light mode; in dark mode
Downloads
4,625
Readme
hb-map
Category: maps · Tags: maps · Package: @htmlbricks/hb-map
Description
hb-map is an interactive map web component built with OpenLayers. You configure center and zoom, a source (OpenStreetMap raster, custom XYZ tiles, or CARTO vector basemaps), options (fit view to markers, label layout), and data for on-map markers (longitude/latitude, optional icon, HTML popup, and optional text label).
The component listens for single clicks: clicks on empty map emit coordinates and current view; clicks on markers open optional popup HTML and emit a marker event. Setting screenshot to yes captures the visible map to PNG and emits a base64 payload when rendering completes.
Basemap sources (source)
Set source as a JSON string (see Attributes).
| source.type | Behavior |
|---------------|----------|
| osm | OpenStreetMap raster tiles. |
| xyz | Raster tiles from source.url (XYZ template with {z}, {x}, {y}). |
| carto_vector | CARTO vector tiles (default tile URL if url is omitted). Styling uses built-in presets. |
CARTO vector: source.style
For carto_vector, source.style may be positron, dark_matter, or voyager when the page uses a light color scheme.
When the component detects a dark scheme, the vector basemap always uses the dark_matter palette, regardless of source.style. Detection order:
hb-map, thendocument.documentElement, thendocument.body:data-theme="dark"or classtheme-dark→ dark;data-theme="light"ortheme-light→ light.- If neither is set explicitly,
prefers-color-scheme: darkselects dark.
The host and document are observed for data-theme and class changes, and the media query is listened to, so the basemap updates when the theme toggles.
CARTO vector: boundaries and labels
boundaries_only: Whentrue, only theboundarylayer is drawn as lines (plus country names from theplacelayer whereclass === "country"). Land, roads, water fills, and other layers are not drawn.national_boundaries_only: Whentrue, only international / country boundaries (OSMadmin_level2) are shown as solid lines. Whenfalse, level 2 stays solid and other allowed levels use a dashed stroke.boundary_admin_levels: Optional JSON array string of numeric admin levels to keep, e.g."[2]"for countries only,"[2,4]"for countries and other divisions present in the tiles. Empty or omitted means no extra filter (all boundary features at the current zoom still pass the national-only rule when that flag applies). Withnational_boundaries_only, the effective set is the intersection with level 2; if the list excludes2, no boundaries render.
Boolean fields in serialized source may use yes / no (or true / false / 1 / 0 for compatibility).
OSM in dark mode
For osm, raster tiles are rendered with a grayscale + invert filter when the same dark detection applies, so the map stays readable on dark UIs.
Marker data (data)
data is a JSON array of objects. Each object may include a marker field. The current implementation renders only marker entries (icons, labels, popups, and click handling). The TypeScript Component type also describes optional point and line shapes for consistency with the schema; those are not drawn by this version of the component.
Marker object (marker)
| Field | Description |
|-------|-------------|
| lngLat | [longitude, latitude] in EPSG:4326 (same order as OpenLayers fromLonLat). |
| icon | Optional: uri (image URL), scale, anchor [x, y], opacity, color (tint). |
| id | Optional string passed through on markerClick. |
| popupHtml | Optional HTML string shown in the map popup when the marker is clicked. |
| text | Optional label next to or around the icon (or alone if there is no icon.uri). |
| text_position | Per-marker override: top, right, bottom, left (default from options.text_position or right). |
| text_offset | Per-marker pixel gap for label placement; falls back to options.text_offset, then an internal default. |
If there is no custom icon and no text, a default pin icon is used.
Options (options)
JSON string. Common fields:
| Field | Description |
|-------|-------------|
| centerFromGeometries | When truthy, the view is centered or fitted from marker positions (fit when there are multiple markers with valid extent). |
| text_position | Default label side relative to the icon: top, right, bottom, left. |
| text_offset | Default pixel gap between icon and label. |
| text_scale | Multiplier for label font size (default scale 1 → base ~13px). |
Screenshots
Set the attribute screenshot="yes" to request a capture after the next render completes. The component dispatches screenshotTaken with { base64 } (PNG data URL). Clear or change the attribute between captures if your host framework does not re-trigger on repeated yes.
Styling (Bulma and host size)
The map canvas sits on a host whose background can follow Bulma’s scheme variable --bulma-scheme-main. Size is controlled by --hb-map-width, --hb-map-height, and fallback --hb-map-default-size (default 200px when width/height are unset). See Bulma CSS variables and extra/docs.ts (styleSetup.vars).
| Variable | Purpose |
|----------|---------|
| --bulma-scheme-main | Background behind the map. |
| --hb-map-default-size | Fallback width and height when explicit size vars are empty. |
| --hb-map-width | Optional explicit host width. |
| --hb-map-height | Optional explicit host height. |
CSS parts
None.
HTML slots
None.
Custom element
hb-map
Attributes (snake_case; string values in HTML)
Web component attributes are strings. Pass objects and arrays as JSON strings. Use yes / no for boolean fields where the project encoding applies; nested source booleans also accept true / false as strings.
| Attribute | Required | Description |
|-----------|----------|-------------|
| id | No | Optional element id. |
| style | No | Optional host inline style (type-level; use CSS variables for layout when possible). |
| zoom | Yes* | Zoom level as a string (e.g. "11"). Parsed to a number internally. |
| center | Yes* | JSON array string: [longitude, latitude] in EPSG:4326. |
| data | Yes* | JSON array of geometry entries; markers use the marker property (see Marker data). |
| source | Yes* | JSON object: at minimum { "type": "osm" \| "xyz" \| "carto_vector", ... } with optional url, style, boundaries_only, boundary_admin_levels, national_boundaries_only for vector tiles. |
| options | Yes* | JSON object for view and label defaults (see Options). |
| screenshot | No | Set to yes to capture the map and emit screenshotTaken. |
*The TypeScript Component type marks these as required for a complete configuration. The implementation still applies defaults when attributes are missing: zoom 6, center [37.5176038, 15.0819224] (same [longitude, latitude] order as elsewhere, passed to fromLonLat), source { type: "osm" }, options {}, data [].
On window resize, the map layout is updated (debounced).
Events
Listen with addEventListener or your framework’s binding. All detail payloads are plain objects.
| Event | detail |
|-------|----------|
| pointClickCoordinates | { coordinates: { latitude, longitude }, zoom, center } — center is [lon, lat] in EPSG:4326 when derived from the view. Emitted when the click does not hit a marker. |
| markerClick | { coordinates: { latitude, longitude }, id? } — id is present when the feature carries marker.id in data. |
| screenshotTaken | { base64 } — PNG data URL string. |
TypeScript (types/webcomponent.type.d.ts)
export type Component = {
id?: string;
style?: string;
zoom: number;
center: number[];
data: {
marker?: {
lngLat: number[];
icon?: {
uri: string;
scale?: number;
anchor?: number[];
opacity?: number;
color?: string;
};
id?: string;
popupHtml?: string;
text?: string;
text_position?: "top" | "right" | "bottom" | "left";
text_offset?: number;
};
point?: {
lngLat: number[];
icon?: {
uri: string;
scale?: number;
anchor?: number[];
opacity?: number;
color?: string;
};
id?: string;
popupHtml?: string;
};
line?: {
lngLat: number[];
icon?: {
uri: string;
scale?: number;
anchor?: number[];
opacity?: number;
color?: string;
};
id?: string;
popupHtml?: string;
}[];
}[];
source: {
type: string;
url?: string;
/**
* Basemap palette for light UI. In dark color scheme (`prefers-color-scheme: dark` or
* `data-theme="dark"` / `.theme-dark` on host or document), `dark_matter` is always used.
*/
style?: "positron" | "dark_matter" | "voyager";
/** When `true`, only the vector `boundary` layer is drawn (no land, roads, water fill, etc.). */
boundaries_only?: boolean;
/**
* Optional JSON array string of OSM `admin_level` values to keep for `boundary` features,
* e.g. `"[2]"` for country borders, `"[2,4]"` for countries plus common internal divisions.
* Omit or empty to show all boundaries present in the tiles at the current zoom.
*/
boundary_admin_levels?: string;
/**
* When `true`, only international / country boundaries (`admin_level` 2) are drawn; internal
* regional lines are hidden. Combines with `boundary_admin_levels` by intersection (e.g. if
* the JSON list excludes `2`, no boundaries render). National lines use a solid stroke;
* when `false`, level 2 stays solid and other levels stay dashed.
*/
national_boundaries_only?: boolean;
};
options: {
centerFromGeometries?: boolean;
text_position?: "top" | "right" | "bottom" | "left";
text_offset?: number;
text_scale?: number;
};
screenshot?: string;
};
export type Events = {
pointClickCoordinates: {
coordinates: { latitude: number; longitude: number };
zoom: number;
center: number[];
};
markerClick: {
coordinates: { latitude: number; longitude: number };
id?: string;
};
screenshotTaken: {
base64: string;
};
};Minimal HTML example
<hb-map
zoom="9"
center="[10,10]"
source='{"type":"osm"}'
options="{}"
data="[]"
></hb-map>Example: CARTO Voyager with markers
<hb-map
zoom="11"
center="[2.3522,48.8566]"
source='{"type":"carto_vector","style":"voyager"}'
options='{"centerFromGeometries":true}'
data='[{"marker":{"lngLat":[2.36,48.86],"text":"Paris"}}]'
></hb-map>Inside JSON strings, use standard JSON booleans (true / false). Truthy string values (e.g. "yes") for centerFromGeometries are also treated as enabled when parsed into a plain object.
