Interactive map
<ullr-map> is the map on its own: pan, zoom and tilt around your mountain with
live trail, lift and terrain park status drawn on top. Visitors can tap an
object to see its detail.
Use it when you already have a conditions page and want a map on it, or when you want the map somewhere the full conditions widget would be too much — a homepage hero, say.

Install
<script type="module" src="https://widget.ullr.ski/web-components/ullr-map.js"></script>
<ullr-map
apiKey="1a2b3c4d5e6f.yourPublishableKey"
areaId="your-area-id"
sport="SNOW"
showTrails="true"
showLifts="true"
showFeatures="true"
initialMapStyle="VECTOR"
units="imperial"
enableCooperativeGestures="true"
style="display:block;position:relative;height:600px"
></ullr-map>The map fills its container and needs an explicit height, or it collapses to nothing.
Set enableCooperativeGestures="true" whenever the map sits inside a page
visitors scroll. Without it, a scroll gesture over the map zooms the map and
traps the reader; with it, they must hold Ctrl (or ⌘) to zoom and an ordinary
scroll moves the page.
Required scopes
resorts:read, plus one per layer you turn on: trails:read, lifts:read,
features:read.
Attributes
Common attributes
Shared by all four embeds.
apiKeystringRequired{id}.{secret}. Sent as the api-key header on every request the element makes. Without it the element logs an error and renders nothing.areaIdstringRequiredsportSNOW | BIKEOptionalSNOWthemestringOptional#6B8CF9. Three- or six-digit hex only; anything else is ignored and the sport default is used. The secondary colour is derived automatically.#6B8CF9 (snow) / #50A162 (bike)timestampnumberOptionalfeatures:readHistory, trails:readHistory, lifts:readHistory. The live scope is not enough on its own: without the history scope the request is refused and the embed renders empty, with no error shown to your visitors. The area itself is always read live, so resorts:read is unchanged.ullrKeystringOptionalapiKey, kept so older snippets keep working. Only read when apiKey is absent. Use apiKey in new code.Map options
showFeaturesbooleanOptionaltrueshowTrailsbooleanOptionalfalseshowLiftsbooleanOptionalfalseinitialMapStyleVECTOR | SATELLITEOptionalVECTOR is the topographic style.VECTORunitsimperial | metricOptionalimperialenableCooperativeGesturesbooleanOptionalfalsemapDefaultLatitudenumberOptionalthe area's configured defaultmapDefaultLongitudenumberOptionalthe area's configured defaultmapDefaultBearingnumberOptionalthe area's configured defaultmapDefaultPitchnumberOptional<ullr-map> always starts at a pitch of 45 — the value set here is overridden. It does work on the [conditions widget](/embeds/conditions-widget).45, and not currently changeableenableMultiSelectbooleanOptionalfalseenableEventsFeatureSelectionbooleanOptionalullr-feature-selected, so embeds on the same page stay in sync when a feature is selected. Switches on both directions at once.falseenableEventsTrailSelectionbooleanOptionalullr-trail-selected, so embeds on the same page stay in sync when a trail is selected. Switches on both directions at once.falseenableEventsLiftSelectionbooleanOptionalullr-lift-selected, so embeds on the same page stay in sync when a lift is selected. Switches on both directions at once.falseEvents
The map both broadcasts selections and responds to them, so it can drive — and be driven by — other embeds on the page. Each event is off until you set the matching attribute above. See syncing embeds with events for the protocol and worked examples.
Emitted
Dispatched on window when a visitor taps something on the map.
ullr-feature-selecteddetail: { featureId: string, senderId: string }enableEventsFeatureSelection.ullr-trail-selecteddetail: { trailId: string, senderId: string }enableEventsTrailSelection.ullr-lift-selecteddetail: { liftId: string, senderId: string }enableEventsLiftSelection.Listened for
Sent by another embed — or by your own code — these move the map.
ullr-feature-selecteddetail: { featureId: string, senderId: string }ullr-trail-selecteddetail: { trailId: string, senderId: string }ullr-lift-selecteddetail: { liftId: string, senderId: string }Notes
- Layer defaults differ from the dashboard. The element shows features only; the dashboard turns on all three and writes them into the snippet.
mapDefaultLatitude,mapDefaultLongitudeandmapDefaultBearingfall back to the area’s configured defaults when out of range or absent — so it is safe to omit them and let the resort’s own framing apply.- Pair the map with a trail list or
lift list and turn on the matching
enableEvents*Selectionattributes on both to keep them in sync — see syncing embeds with events.