Skip to content
+

Create a map component

You can extend Toolpad Studio with custom code components.

You can create a custom component to display any geographical map, like so:

Map component

The map component

Creating the component

In the Toolpad Studio editor

  1. To get started creating this, hover over the component library and click on the Create button in the Custom Components section.
Create custom component

Create a custom component

  1. A dialog box appears asking you to name it. Name it "Map".

Name custom component

Naming a custom component

  1. A snackbar appears acknowledging the successful creation of the component. A starter file is created in toolpad/components. Use the Open button to open this file in your code editor:
Open custom component

Open the custom component

In the code editor

  1. A file with some sample code for a custom component is initialised for you. Replace its content with the following code:
import * as React from 'react';
import { createComponent } from '@toolpad/studio/browser';
import * as L from 'leaflet';

export interface LeafletProps {
  lat: number;
  long: number;
  zoom: number;
}

async function createLeafletStyles(doc) {
  let styles = doc.getElementById('leaflet-css');
  if (styles) {
    return;
  }
  const res = await fetch('https://esm.sh/leaflet/dist/leaflet.css');
  if (!res.ok) {
    throw new Error(`HTTP ${res.status}: ${res.statusText}`);
  }
  const css = await res.text();
  styles = doc.createElement('style');
  styles.id = 'leaflet-css';
  styles.appendChild(doc.createTextNode(css));
  doc.head.appendChild(styles);
}

function Leaflet({ lat, long, zoom }: LeafletProps) {
  const root: any = React.useRef(null);
  const mapRef = React.useRef<any>();
  const [stylesInitialized, setStylesIitialized] = React.useState(false);
  const [error, setError] = React.useState<Error>();

  React.useEffect(() => {
    const doc = root.current.ownerDocument;
    createLeafletStyles(doc).then(
      () => setStylesIitialized(true),
      (err) => setError(err),
    );
  }, []);

  React.useEffect(() => {
    if (!mapRef.current && stylesInitialized) {
      mapRef.current = L.map(root.current);
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '© OpenStreetMap',
      }).addTo(mapRef.current);
    }

    if (mapRef.current) {
      mapRef.current.setView([lat, long], zoom);
    }
  }, [stylesInitialized, lat, long, zoom]);

  return (
    <div style={{ height: 400, width: 600 }}>
      {error ? (
        error.message
      ) : (
        <div style={{ width: '100%', height: '100%' }} ref={root} />
      )}
    </div>
  );
}

export default createComponent(Leaflet, {
  argTypes: {
    lat: {
      type: 'number',
      defaultValue: 51.505,
    },
    long: {
      type: 'number',
      defaultValue: -0.09,
    },
    zoom: {
      type: 'number',
      defaultValue: 13,
    },
  },
});

label and value are the props that you will make available for binding in the Toolpad Studio editor.

  1. MapDisplay is now available as a custom component in the component library:
map component in library

The map component appears in the component library

Using the component

  1. Drag two of the map components on the canvas and select the first one. In the inspector, you'll see both the label and value properties available as bindable properties.
Use map components with numbers and labels

Using the map component