Filter symbols by text input
Replicates the MapLibre example Filter symbols by text input. The places and one symbol layer are YAML; the layer’s filter keeps a place while its icon name contains a query state key. The params panel has no free-text control, so the search box is page chrome in a corner slot, and its JS does one thing: write the key with setGlobalStateProperty.
The YAML half
Section titled “The YAML half”# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json# Gallery twin of https://maplibre.org/maplibre-gl-js/docs/examples/filter-symbols-by-text-input/# The YAML half: the places and ONE symbol layer whose filter reads a# `query` state key — a place shows while its icon name contains the# query. The params panel has no free-text control, so the search box is# page chrome in a corner slot and its JS writes the state key — see# filter-symbols-by-text-input.js. (maplibre-gl >= 5.6 for global-state.)type: mapid: filter-symbols-by-text-inputconfig: center: [-77.04, 38.907] zoom: 11.15 mapStyle: "https://tiles.openfreemap.org/styles/bright"state: query: default: ""layers: - id: poi type: symbol source: type: geojson data: type: FeatureCollection features: - { type: Feature, properties: { icon: theatre }, geometry: { type: Point, coordinates: [-77.038659, 38.931567] } } - { type: Feature, properties: { icon: theatre }, geometry: { type: Point, coordinates: [-77.003168, 38.894651] } } - { type: Feature, properties: { icon: bar }, geometry: { type: Point, coordinates: [-77.090372, 38.881189] } } - { type: Feature, properties: { icon: bicycle }, geometry: { type: Point, coordinates: [-77.052477, 38.943951] } } - { type: Feature, properties: { icon: music }, geometry: { type: Point, coordinates: [-77.031706, 38.914581] } } - { type: Feature, properties: { icon: music }, geometry: { type: Point, coordinates: [-77.020945, 38.878241] } } - { type: Feature, properties: { icon: music }, geometry: { type: Point, coordinates: [-77.007481, 38.876516] } } filter: ["in", ["global-state", "query"], ["get", "icon"]] layout: icon-image: ["concat", ["get", "icon"], "_11"] icon-overlap: always text-field: ["get", "icon"] text-font: ["Noto Sans Regular"] text-size: 11 text-transform: uppercase text-letter-spacing: 0.05 text-offset: [0, 1.5] paint: text-color: "#202" text-halo-color: "#fff" text-halo-width: 2The page half
Section titled “The page half”This markup goes inside <ml-map>; children with a slot ride its corner system.
<div slot="top-right" class="gallery-panel"> <input type="search" data-filter-input placeholder="Filter by name" aria-label="Filter places by name" /></div>The JavaScript half
Section titled “The JavaScript half”// The JavaScript half: one call, setGlobalStateProperty. The layer's filter// already reads the `query` state key (see the YAML), so typing only has// to write the key — no per-layer visibility bookkeeping as upstream does.const mapEl = document.querySelector("ml-map");const input = document.querySelector("[data-filter-input]");
input.addEventListener("input", async () => { const map = await mapEl.mapReady(); map.setGlobalStateProperty("query", input.value.trim().toLowerCase());});What to notice
Section titled “What to notice”- Upstream hides whole layers by id; reading
global-statein one filter replaces that bookkeeping with a single state write. ["in", needle, haystack]on strings is a substring test, and an empty query matches everything.- Needs maplibre-gl ≥ 5.6 for
global-state. For toggles, sliders and selects, the declarative params panel needs no JS — see Filter symbols by toggling a list.