@phila/layerboard
| Install | |
|---|---|
npm install @phila/layerboard |
|
| Latest Version: | 3.3.0 |
| Vue: | 3 |
| Older releases: | 2 |
| License: | MIT |
| Last Updated: | Oct 19, 2026 |
| Links: | GitHub · npm |
@phila/layerboard
A Vue 3 component framework for building interactive map applications powered by ArcGIS Online WebMaps and MapLibre GL JS. Provide a WebMap ID and get a full mapping app with layer management, popups, legends, search, and more.
Live Examples
- OpenMaps — flat layer list (all layers searchable)
- StreetSmartPHL — topic-based layout (layers grouped in accordions)
Installation
pnpm add @phila/layerboard
Peer Dependencies
pnpm add vue pinia maplibre-gl @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/vue-fontawesome
Quick Start
<template>
<Layerboard title="My Map App" web-map-id="1596df70df0349e293ceec46a06ccc50" />
</template>
<script setup>
import { Layerboard } from "@phila/layerboard";
import "@phila/layerboard/dist/layerboard.css";
</script>
This renders a full-screen map app with a sidebar listing all layers from the WebMap, complete with legends, opacity sliders, search, popups, and mobile responsiveness.
Layout Modes
Flat Mode (default)
All layers in a searchable list. Set show-default-sidebar to true (default) and the built-in LayerPanel renders in the sidebar.
Topics Mode
Group layers into collapsible accordions using the sidebar slot:
<Layerboard title="StreetSmartPHL" :web-map-id="webMapId" :show-default-sidebar="false">
<template #sidebar="{ layers, visibleLayers, toggleLayer, setOpacity }">
<TopicAccordion title="Paving" :expanded="true">
<LayerCheckboxSet
:layers="pavingLayers"
:visible-layer-ids="visibleLayers"
@toggle-layer="toggleLayer"
@set-opacity="setOpacity"
/>
</TopicAccordion>
</template>
</Layerboard>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title |
string |
required | App title in header |
webMapId |
string |
required | ArcGIS Online WebMap ID |
subtitle |
string |
— | Subtitle in header |
themeColor |
string |
"#0f4d90" |
Header/footer background color |
showDefaultSidebar |
boolean |
true |
Show built-in LayerPanel (false for custom sidebar) |
sidebarWidth |
string |
"30%" |
Sidebar width (CSS units) |
sidebarLabel |
string |
"Layers" |
Mobile toggle label for sidebar view |
mapLabel |
string |
"Map" |
Mobile toggle label for map view |
fetchMetadata |
boolean |
false |
Fetch layer metadata from Carto |
tiledLayers |
TiledLayerConfig[] |
[] |
ESRI MapServer tiled layers |
dataSources |
DataSourceConfig[] |
[] |
External API data sources |
layerStyleOverrides |
Record<string, LayerStyleOverride> |
{} |
Override paint/legend per layer |
popupOverrides |
Record<string, PopupOverride> |
{} |
Override popup behavior per layer |
initialZoom |
number |
— | Initial map zoom level |
initialCenter |
[number, number] |
— | Initial map center [lng, lat] |
cyclomediaConfig |
CyclomediaConfig |
— | Cyclomedia street-level imagery config |
pictometryCredentials |
PictometryCredentials |
— | Pictometry oblique imagery credentials |
Control Positions
All default to sensible positions. Each accepts "top-left" | "top-right" | "bottom-left" | "bottom-right".
| Prop | Default |
|---|---|
basemapControlPosition |
"top-right" |
navigationControlPosition |
"bottom-right" |
geolocationControlPosition |
"bottom-right" |
searchControlPosition |
"top-left" |
drawControlPosition |
"bottom-left" (or null to remove) |
cyclomediaButtonPosition |
"top-right" |
pictometryButtonPosition |
"top-right" |
Events
| Event | Payload | Description |
|---|---|---|
configs-loaded |
LayerConfig[] |
Layer configs loaded from WebMap |
load-error |
string |
Error message on load failure |
zoom |
number |
Zoom level changed |
Slots
| Slot | Scope | Description |
|---|---|---|
header |
— | Replace default header |
sidebar |
layer state + methods (see below) | Replace default LayerPanel |
footer |
{ openModal, closeModal, isModalOpen } |
Custom footer content |
modal |
{ closeModal } |
Modal content |
Sidebar Slot Scope
The sidebar slot exposes the full layer state for building custom UIs:
{
layers: Array<{ config: LayerConfig; component: string }>
visibleLayers: Set<string>
layerOpacities: Record<string, number>
loadingLayers: Set<string>
layerErrors: Record<string, string>
currentZoom: number
toggleLayer: (id: string) => void
setLayerVisible: (id: string, visible: boolean) => void
setLayersVisible: (ids: string[], visible: boolean) => void
setOpacity: (id: string, opacity: number) => void
// Tiled layers
tiledLayers: TiledLayerConfig[]
visibleTiledLayers: Set<string>
tiledLayerOpacities: Record<string, number>
toggleTiledLayer: (id: string) => void
setTiledLayerVisible: (id: string, visible: boolean) => void
setTiledLayerOpacity: (id: string, opacity: number) => void
// Data sources
dataSourcesState: Record<string, DataSourceState>
dataSourcesLoading: boolean
getDataSource: (id: string) => unknown | null
refetchDataSource: (id: string) => Promise<void>
}
Components
All components are exported for building custom layouts:
import {
Layerboard, // Main framework component
LayerPanel, // Flat layer list with search/legends/opacity
MapPanel, // MapLibre map with layer rendering
TopicAccordion, // Collapsible accordion for topic grouping
LayerCheckboxSet, // Checkbox controls for layer toggling
LayerRadioButtonSet, // Radio buttons for mutually exclusive layers
} from "@phila/layerboard";
Types
All types are exported:
import type {
LayerConfig,
LayerDisplayOptions,
LayerStyleOverride,
LegendItem,
PopupConfig,
PopupField,
PopupOverride,
TiledLayerConfig,
DataSourceConfig,
DataSourceState,
LayerboardConfig,
TopicConfig,
FeatureFlags,
CyclomediaConfig, // re-exported from @phila/phila-ui-map-core
PictometryCredentials, // re-exported from @phila/phila-ui-map-core
} from "@phila/layerboard";
How It Works
- You provide an ArcGIS Online WebMap ID
- Layerboard fetches the WebMap JSON at runtime
- Esri renderers, symbols, scales, and popup configs are transformed into MapLibre-compatible layer configs
- Layers render on a MapLibre GL map — feature data is fetched from ArcGIS FeatureServer endpoints with spatial filtering and pagination
- Server-side geometry simplification (
maxAllowableOffset) scales with zoom level for polygon layers
Development
pnpm install
pnpm build # type-check + vite build
Publishing
pnpm version prerelease # bump beta version
git push origin main
git tag v<version> && git push origin v<version> # triggers publish workflow
Related Packages
Seamless MVT (Mapbox Vector Tile) rendering integration between ArcGIS Maps SDK...
Vue 3 components for MapLibre GL - reactive map components with full TypeScript...
Nuxt module for vue3-maplibre-gl — auto-import components, composables, CSS, and...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 3.3.0 | ^3.5.0 | MIT | |
| 3.2.2 | ^3.5.0 | MIT | |
| 3.2.1 | ^3.5.0 | MIT | |
| 3.2.0 | ^3.5.0 | MIT | |
| 3.1.1 | ^3.5.0 | MIT | |
| 3.1.0 | ^3.5.0 | MIT | |
| 3.0.0 | ^3.5.0 | MIT | |
| 2.2.0 | ^2.7.10 | MIT | |
| 2.1.0 | ^2.7.10 | MIT | |
| 2.0.4 | ^2.7.10 | MIT | |
| 2.0.3 | ^2.7.10 | MIT | |
| 2.0.2 | ^2.7.10 | MIT | |
| 2.0.1 | ^2.7.10 | MIT | |
| 2.0.0 | ^2.6.10 | MIT | |
| 1.1.14 | ^2.6.10 | MIT | |
| 1.1.13 | ^2.6.10 | MIT | |
| 1.1.12 | ^2.6.10 | MIT | |
| 1.1.10 | ^2.6.10 | MIT | |
| 1.1.9 | ^2.6.10 | MIT | |
| 1.1.8 | ^2.6.10 | MIT | |
| 1.1.7 | ^2.6.10 | MIT | |
| 1.1.6 | ^2.6.10 | MIT | |
| 1.1.5 | ^2.6.10 | MIT | |
| 1.1.4 | ^2.6.10 | MIT | |
| 1.1.3 | ^2.6.10 | MIT | |
| 1.1.2 | ^2.6.10 | MIT | |
| 1.1.1 | ^2.6.10 | MIT | |
| 1.1.0 | ^2.6.10 | MIT | |
| 1.0.1 | ^2.6.10 | MIT |
Pre-releases (41)
| Version | Released | Vue | License |
|---|---|---|---|
| 3.3.0-beta.0 | ^3.5.0 | MIT | |
| 3.0.1-beta.1 | ^3.5.0 | MIT | |
| 3.0.0-beta.39 | ^3.5.0 | MIT | |
| 3.0.0-beta.38 | ^3.5.0 | MIT | |
| 3.0.0-beta.37 | ^3.5.0 | MIT | |
| 3.0.0-beta.36 | ^3.5.0 | MIT | |
| 3.0.0-beta.35 | ^3.5.0 | MIT | |
| 3.0.0-beta.34 | ^3.5.0 | MIT | |
| 3.0.0-beta.33 | ^3.5.0 | MIT | |
| 3.0.0-beta.32 | ^3.5.0 | MIT | |
| 3.0.0-beta.31 | ^3.5.0 | MIT | |
| 3.0.0-beta.30 | ^3.5.0 | MIT | |
| 3.0.0-beta.29 | ^3.5.0 | MIT | |
| 3.0.0-beta.28 | ^3.5.0 | MIT | |
| 3.0.0-beta.27 | ^3.5.0 | MIT | |
| 3.0.0-beta.26 | ^3.5.0 | MIT | |
| 3.0.0-beta.25 | ^3.5.0 | MIT | |
| 3.0.0-beta.24 | ^3.5.0 | MIT | |
| 3.0.0-beta.23 | ^3.5.0 | MIT | |
| 3.0.0-beta.22 | ^3.5.0 | MIT | |
| 3.0.0-beta.21 | ^3.5.0 | MIT | |
| 3.0.0-beta.20 | ^3.5.0 | MIT | |
| 3.0.0-beta.19 | ^3.5.0 | MIT | |
| 3.0.0-beta.18 | ^3.5.0 | MIT | |
| 3.0.0-beta.17 | ^3.5.0 | MIT | |
| 3.0.0-beta.16 | ^3.5.0 | MIT | |
| 3.0.0-beta.15 | ^3.5.0 | MIT | |
| 3.0.0-beta.14 | ^3.5.0 | MIT | |
| 3.0.0-beta.13 | ^3.5.0 | MIT | |
| 3.0.0-beta.12 | ^3.5.0 | MIT |
Showing the latest 30 of 41. See every release on npm