Learn how to create a component that switches Calcite Components and ArcGIS Maps SDK for JavaScript in dark mode.
You will use Calcite Components to design an elegant dark mode switch that enables the dark mode for Calcite Components, as well as ArcGIS Maps SDK for JavaScript widgets and basemaps. This application builds on the one created in the Create a mapping app tutorial.
Calcite provides light and dark modes which can be changed using CSS classes: calcite-mode-light
(default) and calcite-mode-dark
. There is also a calcite-mode-auto
class which defers to the browser's CSS prefers-color-scheme media query. Setting the mode class on an element changes all of their child nodes as well.
For more information about mode and styling, visit Calcite Design System's colors and modes foundation and ArcGIS Maps SDK for JavaScript's styling documentation.
Prerequisites
Steps
Create a new pen
- To get started, either complete the Create a mapping app tutorial or .
Use an API key
An API key is required to access ArcGIS services if you are using a developer account. You can skip this step if you have an account associated with an ArcGIS Online organization.
- Go to the get started with security and authentication to build an app that can access secure resources.
- In CodePen >
<script
, import the> esri
class.Config - Set the
api
property.Key
"esri/widgets/Print",
"esri/config"
], function (WebMap, MapView, Bookmarks, BasemapGallery, LayerList, Legend, Print, esriConfig ) {
esriConfig.apiKey = "YOUR_API_KEY";
Add theme stylesheets
The ArcGIS Maps SDK for JavaScript uses separate theme stylesheets. Add both light and dark stylesheets, which will be dynamically toggled in JavaScript using their id
attributes.
- Add the dark theme stylesheet, set the
disabled
attribute, and add anid
. - Add an
id
to the preexisting light theme stylesheet.
<script src="https://js.arcgis.com/calcite-components/2.13.2/calcite.esm.js" type="module"></script>
<link rel="stylesheet" href="https://js.arcgis.com/calcite-components/2.13.2/calcite.css" />
<script src="https://js.arcgis.com/4.31/"></script>
<link disabled id="arcgis-maps-sdk-theme-dark" rel="stylesheet"
href="https://js.arcgis.com/4.31/esri/themes/dark/main.css" />
<link id="arcgis-maps-sdk-theme-light" rel="stylesheet"
href="https://js.arcgis.com/4.31/esri/themes/light/main.css" />
Add HTML
The primary component in the dark mode switch is calcite-switch
. The mode switcher will also use calcite-label
to provide context when the dark mode is toggled.
- In the
calcite-navigation
component, add adiv
element and place it in the Navigation'scontent-end
slot with anid
attribute used later for styling. - Add a
calcite-label
component. Set thelayout
attribute to"inline"
, and add aclass
attribute used later for styling. - Add the
calcite-switch
component.
Read the slots Core concepts section for more information about the concept. After adding CSS in the next step, you can position the dark mode switcher over the map by removing the component from Navigation's content-end
slot.
<body>
<calcite-loader></calcite-loader>
<calcite-shell content-behind hidden>
<calcite-navigation slot="header">
<calcite-navigation-logo id="header-title" heading-level="1" slot="logo">
<!-- Dynamically populated -->
</calcite-navigation-logo>
<div slot="content-end">
<!-- Dark Mode Switch -->
<calcite-label layout="inline" class="label-wrapper">
Dark mode: Off
<calcite-switch></calcite-switch>
On
</calcite-label>
</div>
</calcite-navigation>
Add CSS
At this point, if you run the app you will see the dark mode switcher slotted in the Navigation's "content-end"
slot.
Next, add styling with CSS to position the component using Flexbox.
-
In the
<style
element, add CSS for the dark mode switch's layout by setting the> margin-inline
andpadding
CSS properties. Add a border using the--calcite-color-border-1
CSS variable for the color. Next, add amargin
CSS property to thecalcite-switch
, which will accommodate future controls in the interface.Read the CSS variables Core concepts section for more information about the concept. Calcite's mode colors have both light and dark values, which automatically switch when toggling modes. Use the mode color variables for all non-Calcite elements in applications that switch modes.
-
Next, add the Label's
--calcite-label-margin-bottom
CSS variable to set spacing below and the component and set the Switch'scursor
property to"pointer"
to communicate that the Switch container is clickable.Use dark colors for code blocks .label-wrapper { --calcite-label-margin-bottom: 0px; display: flex; margin-inline: 1rem; padding: 0.5rem; border: 1px solid var(--calcite-color-border-1); cursor: pointer; }
Add JavaScript
Now you have a good looking component; but it doesn't enable dark mode. Next, wire up the dark mode switcher with JavaScript.
- In the
<script
element, below the existing JavaScript code, create a new function to enable dark mode.> - Switch the
calcite-mode-dark
class on the<body
element. No need to add the> calcite-mode-light
class, since it is the default. - Access the ArcGIS Maps SDK for JavaScript light and dark stylesheets using the
id
attributes you added above. - Negate the
disabled
attribute on both stylesheets to toggle their boolean values. - Change the basemap between
gray-vector
anddark-gray-vector
depending on the current mode. - Toggle the
calcite-mode-dark
class across ArcGIS Maps SDK for JavaScript's widgets using.esri-ui
. - Add an event listener to the
calcite-switch
component. Listen for thecalcite
event and provide the function you created.Switch Change
Calcite provides custom events for many of the components. The custom events will all be prefixed with calcite
, then the component name, and finally the type of event. You can check a component's API reference to find out if they have events, and what they are.
document.querySelector("calcite-shell").hidden = false;
document.querySelector("calcite-loader").hidden = true;
const updateDarkMode = () => {
// Calcite mode
document.body.classList.toggle("calcite-mode-dark");
// ArcGIS Maps SDK theme
const dark = document.querySelector("#arcgis-maps-sdk-theme-dark");
const light = document.querySelector("#arcgis-maps-sdk-theme-light");
dark.disabled = !dark.disabled;
light.disabled = !light.disabled;
// ArcGIS Maps SDK basemap
map.basemap = dark.disabled ? "gray-vector" : "dark-gray-vector";
// Toggle ArcGIS Maps SDK widgets mode
const widgets = document.getElementsByClassName("esri-ui");
for (let i = 0; i < widgets.length; i++) {
widgets.item(i).classList.toggle("calcite-mode-dark");
}
};
document.querySelector("calcite-switch").addEventListener("calciteSwitchChange", updateDarkMode);
});
});
</script>
</html>
Run the app
In CodePen, run your code to display the application.
In the top, right corner of the screen you will see the new, beautiful dark mode switcher component. Clicking anywhere on the component will toggle the calcite-switch
. The function you created for the event listener will run, which will toggle Calcite Components in dark mode, as well as the ArcGIS Maps SDK for JavaScript basemap and widgets.