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:
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> ); }
State managed props
Properties of a widget can be managed via react state:
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> ); }
Widgets outside the map
Widgets can also be added outside of the MapView
component using the container
property.
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> ); }
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:
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 />);
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
:
// 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>, );
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 🤞.