The documentation claims that "instead of text also an element (e.g. span) can be used": https://openlayers.org/en/latest/apidoc/module-ol_control_Rotate.html

I tried

this.olMap = new Map({
  // replace arrow with compass icon on rotation button
  controls: defaultControls({
    rotateOptions: {
      autoHide: false,
      className: 'my-compass',
      label: '<svg class="ol-compass compass-svg block w-5 h-5 cursor-pointer select-none z-120" role="button" aria-label="Compass"><use xlink:href="#compass" /></svg>',
      tipLabel: 'Reset GeoMover Rotation'

However, that does not work. Neither does using the class name "compass-svg" or simply the tag. What is the proper use of label with a svg element?


In addition to the accepted solution, I'd like to add an example for incorporating a "use" fragment with svg, which needs special care when generated with Javascript (see https://florianbrinkmann.com/en/svg-use-element-javascript-4513/):

<!-- HTML -->
<!-- A svg element that only "collects" symbols: -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
    <!-- This fragment shall be used for the rotate button -->
    <symbol id="compass" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><g clip-path="url(#clip0)"><path fill="currentColor" d="M10.98 2.19L7.5 11.48a2 2 0 000 1.4l3.47 9.29a1.24 1.24 0 002.31 0l3.47-9.3a2 2 0 000-1.39l-3.47-9.3a1.24 1.24 0 00-2.31 0zm3.15 9.99a2 2 0 11-3.99 0 2 2 0 014 0z"/></g><defs><clipPath id="clip0"><path fill="#fff" d="M0 0h24v24H0z"/></clipPath></defs></symbol>
// JavaScript

// function that returns the svg element
compassIcon () {
  const svgElem = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
  const useElem = document.createElementNS('http://www.w3.org/2000/svg', 'use')

  svgElem.setAttribute('role', 'button')
  svgElem.setAttribute('aria-label', 'compass')
  svgElem.classList.add('ol-compass', 'compass-svg')

  // `#compass` is the id of the svg symbol
  useElem.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#compass')

  return svgElem

// Usage with OpenLayers in Vue
export default {
   data: () => ({
      olMap: null,
   mounted() {
      this.olMap = new Map({
          // add rotate functionality
          interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
          // change rotate button
          controls: defaultControls({
              rotateOptions: {
                  autoHide: false,
                  label: this.compassIcon()

A string will be treated as label text, so an element must be used, which would usually be created using createElement(). If a span element is used an image can defined inside that by setting its innnerHTML property, for example

const span = document.createElement('span');
span.innerHTML = '<img src="compass.png">';

var map = new Map({
  controls: defaultControls({
    rotateOptions: { label: span }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.