Color mode

Map

Turns a ```map fenced code block and/or frontmatter coordinates into an embedded map. The page is rendered with a static fallback first (coordinates, place name, OpenStreetMap links, and an optional static image), and upgraded to an interactive Leaflet map in the browser only when a map is present.

日本語

Configure

ts
import { defineConfig } from "@riebeckite/core";
import { map } from "@riebeckite/plugin-map";
 
export default defineConfig({
  // ...
  plugins: [
    map({
      zoom: 13,
      height: 320,
      // Keyless default; see "Tiles and attribution" before changing it.
      tileUrl: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
      attribution:
        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    }),
  ],
});

The plugin runs with order: -10.

Syntax

Fenced code block

The block body is a small key/value format. A marker list follows markers: as bullets, and a bare lat, lng line is an implicit marker.

markdown
```map
center: 35.6812, 139.7671
zoom: 13
label: Tokyo Station
markers:
  - 35.6812, 139.7671 | Tokyo Station
  - 35.6586, 139.7454 | Tokyo Tower | A lattice tower
```

Marker lines use lat, lng or lat, lng | label | description. The block title becomes the caption when present.

Frontmatter

Coordinates in frontmatter produce one map at the top of the article. The property name defaults to map and is configurable with frontmatterKey.

yaml
---
title: A trip
map:
  lat: 35.6812
  lng: 139.7671
  zoom: 13
  label: Tokyo Station
  markers:
    - 35.6812, 139.7671 | Tokyo Station
    - lat: 35.6586
      lng: 139.7454
      label: Tokyo Tower
---

lat/lng also accept latitude/longitude, coordinates: [lat, lng] or coordinates: "lat, lng", and label also accepts title/place/name.

How it renders

A block or frontmatter map becomes a figure.rr-map:

  • figure.rr-map: carries data-rr-map="pending" and data-rr-map-payload (the resolved map data as JSON)
  • div.rr-map__canvas [data-rr-map-canvas]: the element Leaflet renders into
  • figcaption.rr-map__caption: the caption, when present
  • div.rr-map__static: the always-available fallback, with p.rr-map__place, ul.rr-map__markers → a.rr-map__link (OpenStreetMap links), an optional img.rr-map__image, and p.rr-map__attribution
  • details.rr-map__fallback: the raw block source, folded away

initMap finds every [data-rr-map="pending"], loads Leaflet lazily, draws the tile layer and markers, and flips the figure to data-rr-map="rendered" (the static fallback is then hidden). On failure the figure becomes data-rr-map="error", the details block opens, and the static fallback stays visible.

A block with no coordinates and no center is left as a normal code block, and a diagnostic with source: "@riebeckite/plugin-map" is emitted.

Options

Option Default Description
language "map" Fenced-code language to recognize
className "rr-map" Base class applied to the figure
height 320 Map height in pixels
zoom 13 Default zoom level (0–19)
minZoom 1 Minimum zoom level
maxZoom 19 Maximum zoom level
tileUrl OpenStreetMap standard tiles Tile URL template ({z}/{x}/{y})
attribution OpenStreetMap attribution Attribution HTML required by the provider
fallback true Render the <details> block with the raw source
staticFallback true Render the static fallback block
staticImageUrl — Static image URL template ({lat}/{lng}/{zoom}/{width}/{height})
frontmatterKey "map" Frontmatter property read for coordinates

Tiles and attribution

The default is the keyless OpenStreetMap standard tile layer. It is fine for low-traffic sites, but OpenStreetMap's tile usage policy expects a valid identifying referrer and forbids bulk or heavy use. Sites with meaningful traffic should point tileUrl at their own tile server or a commercial provider.

Attribution is not optional. attribution is passed to Leaflet and rendered in the static fallback (as plain text). Keep the provider's required credit visible.

The plugin ships no API keys or credentials. If a provider's tile or static image URL needs a key, that key travels to the browser and is therefore public; prefer a keyless server or a proxy that keeps the key server-side. Only the tile URL, attribution, and zoom bounds are exposed through publicConfig; no plugin option is copied there implicitly.

Client rendering

Leaflet (leaflet.js + leaflet.css) is fetched from jsDelivr only when at least one [data-rr-map="pending"] figure exists. Because the library is loaded lazily, pages without maps pay nothing, and pages with maps still show the static fallback when JavaScript is disabled or the CDN is unreachable.

initMap(options?) accepts tileUrl, attribution, minZoom, maxZoom, leafletScriptUrl, leafletStyleUrl, and a preloaded runtime (used by tests to inject a fake Leaflet).

Output hooks

  • figure[data-rr-map]: state (pending / rendered / error)
  • figure[data-rr-map-payload]: resolved map data as JSON
  • [data-rr-map-canvas]: Leaflet render target
  • [data-rr-map-static]: static fallback block
  • details.rr-map__fallback: raw block source

Main exports

  • map(options?): create the plugin (mapPlugin is an alias)
  • initMap: initialize client-side maps
  • parseMapSource: parse a fenced block into MapData
  • normalizeMapInput: normalize frontmatter into MapData
  • describeMap, formatCoordinates, openStreetMapUrl
  • Types: MapOptions, MapData, MapMarker, MapPayload, MapClientOptions

Limitations

  • Rendering is client-only. Without JavaScript the page shows the static fallback (coordinates, place, OpenStreetMap links, optional image) but no interactive map.
  • The first interactive render waits on the CDN for Leaflet and the tiles.
  • The tile provider's terms and attribution are the site owner's responsibility.
  • Leaflet is BSD-2-Clause licensed; the default OpenStreetMap tiles are © OpenStreetMap contributors (ODbL).

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/map/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Map
4 +
5 + Turns a ` ```map ` fenced code block and/or frontmatter coordinates into an
6 + embedded map. The page is rendered with a static fallback first (coordinates,
7 + place name, OpenStreetMap links, and an optional static image), and upgraded to
8 + an interactive Leaflet map in the browser only when a map is present.
9 +
10 + [日本語](./map.md)
11 +
12 + ## Configure
13 +
14 + ```ts
15 + import { defineConfig } from "@riebeckite/core";
16 + import { map } from "@riebeckite/plugin-map";
17 +
18 + export default defineConfig({
19 + // ...
20 + plugins: [
21 + map({
22 + zoom: 13,
23 + height: 320,
24 + // Keyless default; see "Tiles and attribution" before changing it.
25 + tileUrl: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
26 + attribution:
27 + '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
28 + }),
29 + ],
30 + });
31 + ```
32 +
33 + The plugin runs with `order: -10`.
34 +
35 + ## Syntax
36 +
37 + ### Fenced code block
38 +
39 + The block body is a small key/value format. A marker list follows `markers:` as
40 + bullets, and a bare `lat, lng` line is an implicit marker.
41 +
42 + ````markdown
43 + ```map
44 + center: 35.6812, 139.7671
45 + zoom: 13
46 + label: Tokyo Station
47 + markers:
48 + - 35.6812, 139.7671 | Tokyo Station
49 + - 35.6586, 139.7454 | Tokyo Tower | A lattice tower
50 + ```
51 + ````
52 +
53 + Marker lines use `lat, lng` or `lat, lng | label | description`. The block
54 + `title` becomes the caption when present.
55 +
56 + ### Frontmatter
57 +
58 + Coordinates in frontmatter produce one map at the top of the article. The
59 + property name defaults to `map` and is configurable with `frontmatterKey`.
60 +
61 + ```yaml
62 + ---
63 + title: A trip
64 + map:
65 + lat: 35.6812
66 + lng: 139.7671
67 + zoom: 13
68 + label: Tokyo Station
69 + markers:
70 + - 35.6812, 139.7671 | Tokyo Station
71 + - lat: 35.6586
72 + lng: 139.7454
73 + label: Tokyo Tower
74 + ---
75 + ```
76 +
77 + `lat`/`lng` also accept `latitude`/`longitude`, `coordinates: [lat, lng]` or
78 + `coordinates: "lat, lng"`, and `label` also accepts `title`/`place`/`name`.
79 +
80 + ## How it renders
81 +
82 + A block or frontmatter map becomes a `figure.rr-map`:
83 +
84 + - `figure.rr-map`: carries `data-rr-map="pending"` and
85 + `data-rr-map-payload` (the resolved map data as JSON)
86 + - `div.rr-map__canvas [data-rr-map-canvas]`: the element Leaflet renders into
87 + - `figcaption.rr-map__caption`: the caption, when present
88 + - `div.rr-map__static`: the always-available fallback, with
89 + `p.rr-map__place`, `ul.rr-map__markers` → `a.rr-map__link` (OpenStreetMap
90 + links), an optional `img.rr-map__image`, and `p.rr-map__attribution`
91 + - `details.rr-map__fallback`: the raw block source, folded away
92 +
93 + `initMap` finds every `[data-rr-map="pending"]`, loads Leaflet lazily, draws the
94 + tile layer and markers, and flips the figure to `data-rr-map="rendered"` (the
95 + static fallback is then hidden). On failure the figure becomes
96 + `data-rr-map="error"`, the `details` block opens, and the static fallback stays
97 + visible.
98 +
99 + A block with no coordinates and no `center` is left as a normal code block, and
100 + a diagnostic with `source: "@riebeckite/plugin-map"` is emitted.
101 +
102 + ## Options
103 +
104 + | Option | Default | Description |
105 + | --- | --- | --- |
106 + | `language` | `"map"` | Fenced-code language to recognize |
107 + | `className` | `"rr-map"` | Base class applied to the figure |
108 + | `height` | `320` | Map height in pixels |
109 + | `zoom` | `13` | Default zoom level (0–19) |
110 + | `minZoom` | `1` | Minimum zoom level |
111 + | `maxZoom` | `19` | Maximum zoom level |
112 + | `tileUrl` | OpenStreetMap standard tiles | Tile URL template (`{z}`/`{x}`/`{y}`) |
113 + | `attribution` | OpenStreetMap attribution | Attribution HTML required by the provider |
114 + | `fallback` | `true` | Render the `<details>` block with the raw source |
115 + | `staticFallback` | `true` | Render the static fallback block |
116 + | `staticImageUrl` | — | Static image URL template (`{lat}`/`{lng}`/`{zoom}`/`{width}`/`{height}`) |
117 + | `frontmatterKey` | `"map"` | Frontmatter property read for coordinates |
118 +
119 + ## Tiles and attribution
120 +
121 + The default is the keyless
122 + [OpenStreetMap standard tile layer](https://tile.openstreetmap.org/). It is fine
123 + for low-traffic sites, but OpenStreetMap's
124 + [tile usage policy](https://operations.osmfoundation.org/policies/tiles/)
125 + expects a valid identifying referrer and forbids bulk or heavy use. Sites with
126 + meaningful traffic should point `tileUrl` at their own tile server or a
127 + commercial provider.
128 +
129 + Attribution is not optional. `attribution` is passed to Leaflet and rendered in
130 + the static fallback (as plain text). Keep the provider's required credit visible.
131 +
132 + The plugin ships no API keys or credentials. If a provider's tile or static
133 + image URL needs a key, that key travels to the browser and is therefore public;
134 + prefer a keyless server or a proxy that keeps the key server-side. Only the
135 + tile URL, attribution, and zoom bounds are exposed through `publicConfig`; no
136 + plugin option is copied there implicitly.
137 +
138 + ## Client rendering
139 +
140 + Leaflet (`leaflet.js` + `leaflet.css`) is fetched from jsDelivr only when at
141 + least one `[data-rr-map="pending"]` figure exists. Because the library is loaded
142 + lazily, pages without maps pay nothing, and pages with maps still show the
143 + static fallback when JavaScript is disabled or the CDN is unreachable.
144 +
145 + `initMap(options?)` accepts `tileUrl`, `attribution`, `minZoom`, `maxZoom`,
146 + `leafletScriptUrl`, `leafletStyleUrl`, and a preloaded `runtime` (used by tests
147 + to inject a fake Leaflet).
148 +
149 + ## Output hooks
150 +
151 + - `figure[data-rr-map]`: state (`pending` / `rendered` / `error`)
152 + - `figure[data-rr-map-payload]`: resolved map data as JSON
153 + - `[data-rr-map-canvas]`: Leaflet render target
154 + - `[data-rr-map-static]`: static fallback block
155 + - `details.rr-map__fallback`: raw block source
156 +
157 + ## Main exports
158 +
159 + - `map(options?)`: create the plugin (`mapPlugin` is an alias)
160 + - `initMap`: initialize client-side maps
161 + - `parseMapSource`: parse a fenced block into `MapData`
162 + - `normalizeMapInput`: normalize frontmatter into `MapData`
163 + - `describeMap`, `formatCoordinates`, `openStreetMapUrl`
164 + - Types: `MapOptions`, `MapData`, `MapMarker`, `MapPayload`, `MapClientOptions`
165 +
166 + ## Limitations
167 +
168 + - Rendering is client-only. Without JavaScript the page shows the static
169 + fallback (coordinates, place, OpenStreetMap links, optional image) but no
170 + interactive map.
171 + - The first interactive render waits on the CDN for Leaflet and the tiles.
172 + - The tile provider's terms and attribution are the site owner's responsibility.
173 + - Leaflet is BSD-2-Clause licensed; the default OpenStreetMap tiles are
174 + © OpenStreetMap contributors (ODbL).
175 +
176 + ## See also
177 +
178 + - [Plugin system](../reference/plugin-api.en.md)
179 +