Docs / Map view / Style adjustments

Style adjustments

Apply adjustments to a map's vector style — roads in white, labels off, darker water — as declarative rules. The same rules work unchanged on Android and iOS.

REACT
@mapconductor/js-vectorstyle
PROP
mapStyle
ESM / CJS
ESM only

01 · Overview

A rule pairs a selector (which layers) with a patch (what to change). Selectors can name a role — roads, water, labels — rather than layer ids. The OpenMapTiles, Shortbread and Mapbox Streets schemas are recognised automatically, so you do not have to look up each style's layer ids.

Pass what createVectorStyle() returns to any *MapView as mapStyle. In React style is the element's own CSS, hence the name (on Android and iOS it is style).

Map
How it applies
What it needs
MapLibre / Mapbox / MapTiler
The map reads the style itself. Changing a rule applies only the difference; no tile is reloaded.
This package alone
Everything else (Google Maps, Leaflet, OpenLayers, ArcGIS, Cesium, HERE, MapKit, deck.gl…)
The style is drawn into raster tiles and layered on.
VectorTileRasteriser as the rasteriser

Hand it to a map that cannot read vector styles without a rasteriser and the diagnostics say the style is unsupported, rather than the map quietly drawing nothing.

02 · Install

terminalnpm
npm install @mapconductor/js-sdk-core @mapconductor/js-vectorstyle

To use it on maps without a vector renderer, add react-vectortile for the rasteriser too (and set up the Service Worker described in vector tile layer).

terminalnpm
npm install @mapconductor/react-vectortile

ESM only. The rules compiler is wasm (about 190 KB), loaded relative to import.meta.url; Vite handles that as is. Serve it from elsewhere with wasmUrl.

03 · Basic usage

Leave out document and the style the map is already drawing ('currentDesign') is adjusted. The example turns MapLibre's default design into a black-and-white map of roads.

RoadsOnlyMap.tsxTypeScript · React
import { useMemo } from 'react';
import { buildStyleRules, createVectorStyle, LayerRole } from '@mapconductor/js-vectorstyle';
import { MapLibreMapView2D, useMapLibreViewState } from '@mapconductor/react-for-maplibre';

export function RoadsOnlyMap() {
  const state = useMapLibreViewState();
  const mapStyle = useMemo(
    () => createVectorStyle({
      rules: buildStyleRules((r) => {
        r.all({ color: '#000000' });
        r.role(LayerRole.label, { visible: false });
        r.role(LayerRole.roadCasing, { color: '#303030' });
        r.role(LayerRole.road, { color: '#ffffff', widthScale: 1.4 });
      }),
    }),
    [],
  );

  return (
    <MapLibreMapView2D
      state={state}
      mapStyle={mapStyle}
      onStyleDiagnostics={(messages) => console.warn(messages)}
    />
  );
}

For a style of your own, pass { url } or { text } as document.

04 · Writing rules

Rules apply in order and, as in CSS, a later rule wins property by property. Set the whole map with all, then override by role.

TypeScriptTypeScript
buildStyleRules((r) => {
  r.all({ colorFilter: { darken: 0.55 } });
  r.role(LayerRole.water, { color: 'rgb(10,28,43)' });
  r.role(LayerRole.road, { color: '#d0d0d0' });
  r.layerId('poi-*', { visible: false });
  r.kind('symbol', { opacity: 0.8 });
});
Selector
Builder
Description
all
r.all(patch)
Every layer.
{ role }
r.role(LayerRole.road, patch)
A role: background, water, waterway, land, landuse, park, building, road, road-casing, rail, transit, boundary, aeroway, label, poi.
{ layerId }
r.layerId('poi-*', patch)
Layer id, with * and ? wildcards.
{ sourceLayer }
r.sourceLayer('water', patch)
The tiles' source-layer name.
{ kind }
r.kind('symbol', patch)
Layer kind: background, fill, line, circle, symbol, other.
anyOf / allOf / not
r.where(selector, patch)
Combinations.
Patch
Type
Description
visible
boolean
Show or hide.
color
string
The colour that fits the layer kind (fill, line, text and icon, background).
colorFilter
{ desaturate } | { darken } | { lighten } | { invertLightness } | { mix }
A transform of the original colour.
opacity
0–1
Opacity.
widthScale
number
Multiplier on line width and circle radius.
filter
MapLibre expression
Replaces the layer's filter.
minZoom / maxZoom
number
Zoom range shown.
properties
Record<string, unknown>
Any style-spec property by name, applied last.

Rules as JSON

Rules are also a JSON document. To serve them from a server or keep them across app versions, store them in this form and read them with parseStyleRules(). Android and iOS read the same document.

night.rules.jsonJSON
{
  "schemaVersion": 1,
  "rules": [
    { "selector": "all", "patch": { "colorFilter": { "darken": 0.55 } } },
    { "selector": { "role": "water" }, "patch": { "color": "rgb(10,28,43)" } }
  ]
}
TypeScriptTypeScript
import { createVectorStyle, parseStyleRules } from '@mapconductor/js-vectorstyle';

const rules = parseStyleRules(await (await fetch('/night.rules.json')).text());
const mapStyle = createVectorStyle({ rules });

05 · On maps without a vector renderer

Pass a VectorTileRasteriser as rasteriser and the style is drawn into raster tiles and layered on. Blank the provider's own basemap with its None design.

TypeScriptTypeScript · React
import { useMemo } from 'react';
import { createVectorStyle } from '@mapconductor/js-vectorstyle';
import { VectorTileRasteriser } from '@mapconductor/react-vectortile';
import { GoogleMapDesign, GoogleMapView2D, useGoogleMapViewState } from '@mapconductor/react-for-googlemaps';

const state = useGoogleMapViewState({
  apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
  mapDesignType: GoogleMapDesign.None,
});
const rasteriser = useMemo(() => new VectorTileRasteriser(), []);
const mapStyle = useMemo(
  () => createVectorStyle({
    document: { url: 'https://tiles.versatiles.org/assets/styles/colorful/style.json' },
    rules,
    rasteriser,
  }),
  [rules, rasteriser],
);

<GoogleMapView2D state={state} mapStyle={mapStyle} style={{ height: 480 }} />
CAUTION
The rasteriser is compared by identity. Creating a new one on every render looks like a different style and rebuilds the map each time — hold a single instance, with useMemo or similar.

06 · Options

Option
Default
Description
document
'currentDesign'
The style to adjust: { url, headers? }, { text } or 'currentDesign'.
rules
—
The rules to apply. NO_STYLE_RULES keeps the style as authored.
rasteriser
—
Draws the style on maps without a vector renderer.
onUnsupported
'report'
When the map will not take a difference. 'reload' hands it the whole adjusted document — correct, but expensive.
onDiagnostics
—
How many layers matched, rules that matched nothing, adjustments the map refused.
wasmUrl
—
Where the compiler wasm is served from.

Diagnostics also arrive through the *MapView's onStyleDiagnostics; without it they go to the console. A rule that matched nothing only looks like "it nearly worked", so keep them visible while you build.

Related pages