map0

New map0-viewer 0.3.0 is out: WFS, OGC API Features and GeoParquet layers, GeoJSON, KML and GPX by URL or from local files, feature information as a bottom sheet on phones, and a series of fixes. Release notes →

Open source · built on MapLibre GL JS · web component · made in the EU

map0

The web map client you configure, not code.

Embed a web map with basemaps, a layer tree, legends, popups, search and print. Configure it in a single JSON document and add it to your page.

Try the map. It combines WMS, vector tiles and GeoJSON points from a WFS. Open the layer tree, show the zoning plan, click a fountain, switch to aerial imagery, search for an address or measure a distance. The configuration is shown below.

~34 KB gzip on page load, before the map comes into view
118 config keys in one JSON document, checked against a schema
10 source types, from WMS, WFS and OGC API Features to PMTiles, COG and GeoParquet
24 demos running against live public services

Why map0

Map controls and tools, ready to embed.

map0 combines MapLibre rendering with a layer tree, legends, popups and print tools. A JSON config defines the map, and a web component displays it inside your existing website.

🧩

It is a web component

<map0-viewer> is a standard custom element with its own Shadow DOM. Use it in a CMS, Next.js, Vue or a plain HTML page. Its styles are isolated from the surrounding page.

⌨️

Everything is configuration

Basemaps, overlays, popups, legends, print layout, theme and languages are configured in one JSON document. Store it as a file or in a CMS field.

🪶

Light on the page

An embedded map initially adds about 34 KB gzip. The map engine and MapLibre load as the map approaches the viewport. Measuring, printing and coordinate tools load when first used.

📱

At home on every screen

The interface adapts to the map’s container, from a narrow phone screen to a wide desktop layout. Controls support touch and mouse input, and the colour scheme can follow the operating system.

Quick start

A basemap and a WMS overlay in one file.

Add a script tag to register the custom element, then include the element with its config. The example below is generated from the map beside it.

the whole page

Copy this example into an HTML page. It loads a specific release from the CDN, since the config format may change before version 1.0. The optional $schema entry enables editor completion and validation when the config is stored in a separate JSON file.

index.html
<script type="module"
        src="https://cdn.jsdelivr.net/npm/map0-viewer@0.3.0/dist/map0.js">
</script>

<map0-viewer style="height:520px">
  <script type="application/json">
    {
      "$schema": "https://map0.net/schema/v1.json",
      "version": 1,
      "map": { "center": [16.3689, 48.2015], "zoom": 15.2 },
      "basemaps": [
        {
          "type": "style",
          "url": "https://mapsneu.wien.gv.at/basemapv/bmapv/3857/resources/styles/root.json"
        }
      ],
      "layers": [
        {
          "type": "wms",
          "title": "Tree register",
          "url": "https://data.wien.gv.at/daten/geo",
          "layers": "BAUMKATOGD",
          "minZoom": 15,
          "info": { "format": "application/json" }
        }
      ]
    }
  </script>
</map0-viewer>

Edit this map in the playground →

the result

An interactive map using the configuration shown in the example.

What those few lines bought

The viewer includes zoom, compass, scale bar, fullscreen, location, globe view, attribution, a layer tree with opacity controls, legends, feature information, coordinates, measuring, print and export. The colour scheme follows the operating system by default.

Three ways to hand over the config

Config sources are checked in this order: the JavaScript config property, the config-src attribute pointing to a JSON file, and a <script type="application/json"> child inside the element, as shown above.

Or host it yourself

Install with npm install map0-viewer, copy node_modules/map0-viewer/dist to your web server and point the script’s src there. Keep the folder’s files together: the entry loads its modules and MapLibre’s worker from relative paths. See the README for details.

Batteries included

Map tools configured in JSON.

These tools are included in the viewer. Enable and configure them in JSON. Each card links to a demo with its configuration.

🗺️ Map services and data files

WMS with feature information, WMTS configured from capabilities, WFS and OGC API Features with paging, vector tiles and PMTiles, GeoJSON with clustering, and GeoParquet decoded in the browser.

See the data source demos →

🌳 Layer tree

Group layers, adjust visibility and opacity, view status and zoom limits, zoom to a layer and open its metadata. Users can add WMS, WMTS and GeoJSON URLs or import local GeoJSON, KML and GPX files.

See add layers →

💬 Feature information

Display attributes in templates with {{placeholders}} or in tables. Add hover tooltips, combine results from several layers in one popup and highlight selected features. Popup HTML is sanitised before display.

See popups & hover →

📊 Legends, on screen and on paper

Service legends via GetLegendGraphic, swatches derived from the style itself, or hand-written entries when a service has no legend worth showing.

See legends →

🖨️ Print & export

Export high-resolution PNG images or PDF pages in A4 and A3. Configure the title, legend, scale bar, attribution and date. The browser creates the output.

See print & export →

🔍 Place and address search

Search with suggestions using Photon or Nominatim, hosted publicly or on your own server. Custom geocoders can be configured with a URL template. Coordinate input is also supported.

See search →

📏 Measuring and coordinates

Measure distances and areas with movable vertices. Right-click to display and copy coordinates in WGS84, Gauß-Krüger and UTM.

See measuring →

🔗 Share links and globe view

Share the view, basemap, layer settings and services added by URL through a link. Enable globe view in the config to offer a second map projection.

See share & permalink →

Performance

Nothing loads until the map is on screen.

map0 loads in three stages: the page component, the map engine and tools used on demand. Automated checks enforce a size budget for the initial download.

Page load
~34 KB gz
Map enters the viewport
+ ~317 KB gz
First use of a feature
0.2–136 KB gz each

What that means in practice

Initially, the page loads the custom element and Lit. Map loading starts 300 px before the element reaches the viewport. Several maps share the same engine files. A map inside a hidden tab waits until the tab is shown.

Features are chunks

Capabilities parsing, proj4, PMTiles, the print composer and the add-layer dialog are separate files. A map without measuring never downloads the measuring code.

See it in the network panel →

And once it is there, the GPU draws it.

MapLibre uses WebGL 2 to render the map on the graphics processor. Vector geometry and labels are drawn in the browser, while raster services supply their own images.

🎞️

Smooth, not stepped

Zoom smoothly between levels, pan the map, or rotate and tilt the view. MapLibre updates the scene as the camera moves.

🏷️

Cartography at runtime

MapLibre places labels and checks for collisions while rendering. Style expressions control colours, line widths and filters for vector features. Changes can reuse the vector data already loaded.

🌍

Globe projection

Enable globe view with one config setting. MapLibre renders the same data and styles using the globe projection.

Config-first

One document. Schema-validated. Inheritable.

This is the configuration for the map at the top of the page, read from the same file the viewer uses.

vienna.map0.json
{
  "$schema": "https://map0.net/schema/v1.json",
  "version": 1,
  "meta": { "title": "Vienna, three sources, one document" },
  "map": { "center": [16.3725, 48.2083], "zoom": 12.2, "cooperativeGestures": true },
  "basemaps": [
    {
      "id": "grau",
      "title": "Grey",
      "type": "raster",
      "url": "https://mapsneu.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png",
      "attribution": "© basemap.at",
      "default": true
    },
    {
      "id": "bmapv",
      "title": "basemap.at",
      "type": "style",
      "url": "https://mapsneu.wien.gv.at/basemapv/bmapv/3857/resources/styles/root.json"
    },
    {
      "id": "ortho",
      "title": "Aerial",
      "type": "raster",
      "url": "https://mapsneu.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/{z}/{y}/{x}.jpeg",
      "maxZoom": 19,
      "attribution": "© basemap.at"
    }
  ],
  "layers": [
    {
      "id": "widmung",
      "type": "wms",
      "title": "Zoning plan (WMS)",
      "url": "https://data.wien.gv.at/daten/geo",
      "layers": "GENFLWIDMUNGOGD",
      "visible": false,
      "opacity": 0.55,
      "info": { "format": "application/json" },
      "legend": "auto",
      "metadata": {
        "url": "https://www.data.gv.at/katalog/dataset?q=Fl%C3%A4chenwidmung+Wien",
        "title": "Dataset on data.gv.at"
      },
      "attribution": "Stadt Wien, data.wien.gv.at"
    },
    {
      "id": "gewaesser",
      "type": "vector",
      "title": "Water bodies (vector tiles)",
      "url": "https://mapsneu.wien.gv.at/basemapv/bmapv/3857/",
      "sourceLayer": "GEWAESSER_F_GEWF",
      "style": [
        {
          "type": "fill",
          "paint": { "fill-color": "#0ea5e9", "fill-opacity": 0.6 }
        }
      ],
      "legend": [{ "label": "Water body", "color": "#0ea5e9" }],
      "attribution": "© basemap.at"
    },
    {
      "id": "brunnen",
      "type": "geojson",
      "title": "Drinking fountains (GeoJSON)",
      "data": "https://data.wien.gv.at/daten/geo?service=WFS&request=GetFeature&version=1.1.0&typeName=ogdwien:TRINKBRUNNENOGD&srsName=EPSG:4326&outputFormat=json",
      "style": {
        "circle-color": "#0e7490",
        "circle-radius": 4,
        "circle-stroke-color": "#ffffff",
        "circle-stroke-width": 1.2
      },
      "popup": {
        "title": "{{BASIS_TYP_TXT}}",
        "fields": [{ "key": "BEZIRK", "label": "District" }]
      },
      "legend": [
        {
          "label": "Drinking fountain",
          "color": "#0e7490",
          "shape": "circle"
        }
      ],
      "attribution": "Stadt Wien, data.wien.gv.at"
    }
  ],
  "search": {
    "provider": "photon",
    "country": "AT",
    "coordinates": true
  },
  "theme": { "primary": "#0e7490", "radius": "md" }
}

Reuse a base configuration

Keep each map’s settings in one JSON document. Use extends to inherit shared defaults from a base config and specify only the settings that differ.

Find configuration errors

The viewer validates the config before rendering. Errors appear in the viewer with the JSON path of the affected setting.

error panel
$.basemaps          at least one basemap is required, e.g. { "type": "style", "url": "…" }
$.layers[2].url     a "wms" layer needs a "url"
$.layers[2].layers  a "wms" layer needs "layers" (WMS LAYERS parameter)

Themed and translated

A primary color, a radius, a font and light/dark come from the config or from your page's CSS custom properties. The UI ships in German and English, and every single string can be overridden per locale.

Theming →  Languages →  Inheritance →

Where it sits

Where map0 fits

Geoportals, portal frameworks and map libraries cover different needs. map0 provides a configurable viewer that embeds in an existing website. The table compares these approaches.

Aspect Geoportal platform Portal framework Map library map0
What it is An application you host A configurable app to set up A rendering engine A component on your page
Embedding An iframe Its own page or an iframe Whatever you build Script tag + one element
Configuration Backend or database Several files and a registry Source code One JSON document
Server needed Yes No, but a build setup No Static hosting is sufficient
TOC, legends, print Included Included Build it yourself Included
Who changes the map Someone with server access A developer A developer Anyone with the text field
Look and feel The portal's The framework's Yours to build Themed to your page

What's next

Planned features

map0 is in active development. The following features are planned for future releases.

♿ Accessibility audit

Keyboard operation, focus handling and reduced motion are in. What follows is the audit: the layer tree fully keyboard-driven, and feature results mirrored into the DOM so a screen reader can read what the map draws.

🏔️ 3D terrain

Elevation data already supports hillshading. Terrain support will add a three-dimensional surface with map overlays rendered over it.

🔐 Protected services

A hook for request tokens and headers will let applications provide credentials for protected WMS, WMTS and vector tile services.

⚛️ React and Angular wrappers

The custom element already supports framework integration, with TypeScript declarations included in the package. Dedicated wrappers will add framework-specific properties, events and SSR integration.

🖨️ Scale-true print

The browser exports PNG and PDF pages. A planned server adapter will support printing at a specified map scale, such as 1:5,000.

🎛️ The map0 configurator

A visual editor for selecting services, arranging layers and configuring popups, legends and themes, with a map preview. The resulting JSON can be copied into a CMS.

🧩 Plugin API

A documented API for adding custom layer adapters, tools and panels.

🗂️ Catalog search

Search CSW or OGC API Records metadata catalogues and add the selected service as a map layer.

Also on the list: drawing and annotations, time-enabled layers (WMS TIME), drag-reorder and a filter box in the layer tree, and a deck.gl overlay for very large datasets. The full picture lives in the repository, and if something you need is missing, an issue is the fastest way to influence the order.

Questions and answers

The short version.

What people ask before they embed their first map. The details live in the demos and in the README.

What is map0?

map0 is an open-source web map client released under the MIT license. It is a web component built on MapLibre GL JS: one script tag and one JSON document put a complete map with basemaps, layer tree, legends, feature info, search, measuring and print on any web page. There is no iframe, no backend and no build step.

Which services and data formats can a map show?

WMS, WMTS, WFS and OGC API Features, vector tiles as MVT or PMTiles, GeoJSON, GeoParquet and Cloud Optimized GeoTIFF. Basemaps are MapLibre style URLs or raster tile services. Visitors can add WMS and WMTS services by URL and bring GeoJSON, KML and GPX along as a URL or a local file.

How do I embed a map in my website or CMS?

Load the map0-viewer package with one module script tag, from a CDN such as jsDelivr or from your own server after npm install map0-viewer, and place a <map0-viewer> element where the map should appear. The configuration is an inline JSON script, a config-src attribute pointing at a JSON file, or a JavaScript property. Because it is a standard custom element it works in plain HTML, in any CMS field that accepts HTML, and in every framework.

Do I need a server, a database or a build step?

No. Static hosting is enough. The map renders in the browser and talks directly to your map services, which therefore have to send CORS headers. map0 itself sends nothing anywhere: no analytics, no cookies, no tracking.

How is a map configured?

In a single JSON document, validated against the published JSON Schema at map0.net/schema/v1.json. Basemaps, layers, popups, legends, search, measuring, print, theme and languages are all keys in that document, and a map can inherit from a shared base config with extends. A broken config is reported before anything renders, with the JSON path of each error. The playground lets you edit a config and watch the map follow.

How does map0 relate to MapLibre GL JS?

MapLibre is the rendering engine inside map0. map0 adds the application around it: layer tree, legends, popups, search, measuring, print, permalinks and theming, all driven by the config instead of code. MapLibre style URLs work as basemaps as they are, and vector layers are styled with the MapLibre style specification.

Is map0 free, also for commercial use?

Yes. map0 is released under the MIT license and can be used, modified and redistributed free of charge, in commercial and public-sector projects alike. The source code is on GitHub. map0 is developed by Spatial Focus GmbH in Vienna, Austria.

Is map0 ready for production?

map0 is a 0.x release. Everything on this page works against live services and the demos on this site run on it, but the JavaScript API and the config format are still drafts and may change without a deprecation path until 1.0. Pin an exact version and read the changelog when you upgrade.

Which languages, screens and themes are supported?

The UI ships in English and German, and every string can be overridden per locale from the config. The component is responsive from a 320 px phone to a 4K display, shows feature info as a bottom sheet on small screens, and follows the operating system's light or dark mode. Primary colour, corner radius and font come from the config or from your page's CSS custom properties.

Demos

24 demos. Live services. The exact config each one runs.

Each demo covers one topic and includes an interactive map, an explanation and its configuration. Open a demo to try the features and reuse the settings.