Skip to main content

Widgets

As map children

Widgets can be added to a MapView as children. They take all the same properties as their native ArcGIS JS API instance:

Live Editor
function Example() {
  return (
    <MapView
      ViewProperties={{ extent: OAHU_EXTENT }}
      MapProperties={{ basemap: "topo-vector" }}
      style={{ height: "400px", width: "100%" }}
    >
      <FeatureLayer url={BENTHIC_FEATURELAYER_URL} />

      <SearchBar position="top-right" />
      <Legend position="top-right" />
    </MapView>
  );
}
Result
Loading...

State managed props

Properties of a widget can be managed via react state:

Live Editor
function Example() {
  const [checked, setChecked] = useState(true);
  return (
    <div>
      <div>
        <label className="flex gap-2 mb-2 items-center">
          <input
            type="checkbox"
            checked={checked}
            onChange={(e) => setChecked(e.target.checked)}
          />
          Legend: Respect Definition Expression
        </label>
      </div>

      <MapView
        ViewProperties={{ extent: OAHU_EXTENT }}
        MapProperties={{ basemap: "topo-vector" }}
        style={{ height: "400px", width: "100%" }}
      >
        <FeatureLayer
          url={OAHU_HPMS_ROADS_FL_URL}
          definitionExpression="f_system_t = 'Interstate'"
        />

        <Legend
          position="top-right"
          key={`${checked}`}
          respectLayerDefinitionExpression={checked}
        />
      </MapView>
    </div>
  );
}
Result
Loading...

Widgets outside the map

Widgets can also be added outside of the MapView component using the container property.

Live Editor
function Example() {
  return (
    <div className="flex gap-2">
      <MapView
        ViewProperties={{ extent: OAHU_EXTENT }}
        MapProperties={{ basemap: "topo-vector" }}
        style={{ height: "400px", width: "100%" }}
      >
        <Legend position="top-right" container="legend-container" />

        <FeatureLayer
          url={BENTHIC_FEATURELAYER_URL}
          definitionExpression="zone = 'Back Reef'"
        />
      </MapView>
      <div className="w-[300px] border border-green-500 bg-white">
        <h4 className="text-center m-1">Outside the map</h4>
        <div
          id="legend-container"
          className="w-full max-h-[400px] overflow-y-auto"
        />
      </div>
    </div>
  );
}
Result
Loading...

Widgets elsewhere in the tree

In the above example, the semantics of the component tree are a bit odd. The Legend is declared as a child of the MapView. You can have a component tree that matches your UI more closely by using the MapViewContext and a careful combination of container and view props:

Live Editor
function OtherUI() {
  const { view } = useMap();

  return (
    <nav className="border-blue-800 border p-2">
      <h4>Elsewhere in the component tree</h4>

      <div
        id="legend-container-2"
        className="w-full max-h-[300px] overflow-y-auto"
      >
        {view && <Legend container="legend-container-2" view={view} />}{" "}
      </div>
    </nav>
  );
}

function Example() {
  return (
    <MapContextProvider>
      <div className="flex gap-2">
        <OtherUI />

        <div className="flex-1 border-green-800 border items-stretch">
          <MapViewCore
            ViewProperties={{ extent: OAHU_EXTENT }}
            MapProperties={{ basemap: "topo-vector" }}
            style={{ height: "100%", width: "100%" }}
          >
            <FeatureLayer url={BENTHIC_FEATURELAYER_URL} />
          </MapViewCore>
        </div>
      </div>
    </MapContextProvider>
  );
}

render(<Example />);
Result
Loading...

Integration with web components

During development of this library, esri announced their plan to transition away from classic widgets, to standard web components. These standard web components make development with react much more intuitive for UI elements like widgets. This library has not yet been brought up to date to be based on web-components. In the meantime, you can either use the class (but soon to be deprecated) widgets as shown above, or you can mix in the newer web-components. You can declare a web component widget in your map, but you must manually add the widget to the view:

Live Editor
// import "@arcgis/map-components/components/arcgis-directional-pad";

function Provider({ children }) {
  return <MapContextProvider>{children}</MapContextProvider>;
}

function Example() {
  const { view } = useMap();

  useEffect(() => {
    if (view?.when) {
      view.when(() => {
        const pad = document.querySelector("arcgis-directional-pad");
        pad.view = view;
        view.ui.add(pad, "top-right");
      });
    }
  }, [view]);

  return (
    <MapViewCore
      ViewProperties={{ extent: HAWAII_EXTENT }}
      MapProperties={{ basemap: "topo-vector" }}
      style={{ height: "300px", width: "100%" }}
    >
      <arcgis-directional-pad></arcgis-directional-pad>
    </MapViewCore>
  );
}

render(
  <MapContextProvider>
    <Example />
  </MapContextProvider>,
);
Result
Loading...

Once this library has been brought up to date with the still-emerging web component standard, and its mixture with React 19, the useEffect in the above example will no longer be necessary 🤞.