Core concepts

Calcite Components is a library of reusable web components built using Stencil.js. With Calcite Components, you can quickly build on-brand, lightweight, and accessible web applications.

Web components are a native browser standard, and many of the technical concepts necessary to develop with Calcite Components are not specific to the library. This page provides an introduction to key web concepts, which are necessary for effective development. For further reading, all of the concepts on this page can be found on MDN Web Docs and other web standard documentation sources.

Custom elements

Custom elements are part of the Web Components standards, which work across modern browsers using any JavaScript library or web framework with HTML. Custom elements encapsulate functionality, which prevents conflicts with the rest of your code.

Calcite Components are custom elements and can be used similar to native HTML elements. For instance:

Use dark colors for code blocksCopy
 
1
<calcite-tip heading="Platypus"></calcite-tip>

Slots

Slots are placeholder elements that allow you to add your own content by referencing the slot's name. Slots are a common web components concept, and chances are you already use them. For example, take the following HTML:

Use dark colors for code blocksCopy
     
1
2
3
4
5
<select>
  <option value="platypus">Platypus</option>
  <option value="sloth">Sloth</option>
  <option value="armadillo">Nine-banded armadillo</option>
</select>

In web component terminology, the option elements are placed in select's default slot. Additionally, the "Platypus", "Sloth", and "Nine-banded armadillo" text is placed in option's respective default slots.

Many Calcite Components also utilize default slots. For instance, in the calcite-tip below, the p content is added to the default slot:

Use dark colors for code blocksCopy
    
1
2
3
4
<calcite-tip heading="Platypus">
  <img slot="thumbnail" src="platypus.jpg" alt="A platypus sensing its prey using electrical fields." />
  <p>A platypus is a mammal with a bill, similar to a duck. They use their bill to sense prey via electrolocation.</p>
</calcite-tip>

In many cases, a default slot is all that is needed. However, as components become more complicated, the need arises to position and style child elements differently. This is where named slots come into play. In the example above, an image is placed into the tip's thumbnail slot. This informs the component that the image should be handled differently than the elements in the default slot.

If a component has slots, they will be listed in the documentation, such as the slots for calcite-card. You can also learn more about slots on MDN.

Shadow DOM

Custom elements are encapsulated, which keeps their markup structure, style, and behavior hidden and separate from other code on the page. The Shadow DOM is the mechanism that encapsulates custom elements. As a result, Shadow DOM hides and separates a web component's DOM elements, so they are rendered in the browser, but do not clash with the rest of your code.

The Shadow DOM encapsulation creates persistent styling and functionality across your applications, enabling your users to have a consistent user experience.

CSS variables

Calcite Components provides CSS variables to override styles. Due to web components' shadow DOM, the styles can not be easily altered without CSS variables. There are CSS variables for tokens that are used throughout the design system, including color and typography.

Additionally, some Calcite Components have their own CSS variables to change component-specific styles. These CSS variables can be found in a component's documentation, such as the CSS variables for calcite-loader.

An example use case is swapping the foreground and text colors in calcite-notice using CSS variables.

Use dark colors for code blocksCopy
    
1
2
3
4
calcite-notice {
  --calcite-ui-foreground-1: #151515;
  --calcite-ui-text-1: #ffffff;
}

The CSS variable MDN documentation provides a detailed explanation of the functionality.

Loading components

Web components start as plain HTML elements, and are upgraded as soon as their implementations are defined in the browser. Calcite Components are automatically defined when they are imported and used in an application. However, sometimes it is necessary to wait until a component is defined before executing specific code.

Hydration

Stencil.js provides the option to add a flag when a component and all of its child components have finished hydrating. This helps prevent any flash of unstyled content (FOUC) as various components are asynchronously loaded and rendered. In Calcite Components, the calcite-hydrated CSS class is added to components once they are hydrated, and is useful when debugging your application.

When defined

The whenDefined() method of the customElementRegistry interface returns a promise, which is fulfilled when the specified element is defined.

Once the promise is fulfilled, you can run code that requires the component to be defined, like so:

Use dark colors for code blocksCopy
 
1
customElements.whenDefined("calcite-button").then(() => document.querySelector("calcite-button").setFocus());

Component on ready

To determine when a component is rendered, you can use Stencil's componentOnReady() method. The method returns a Promise that resolves after the componentDidLoad() lifecycle method fires. It is useful for making sure a component is loaded before using it's methods, or when one component is dependent on another.

For example, you may want to display calcite-loader until other component(s) finish rendering:

Use dark colors for code blocksCopy
     
1
2
3
4
5
(async () => {
  await customElements.whenDefined("calcite-alert");
  await document.querySelector("calcite-alert").componentOnReady();
  document.querySelector("calcite-loader").hidden = true;
})();

Calling a component's method as the callback of requestAnimationFrame ensures the user interface updates with the component's state. For example, if you want to set the current step for calcite-stepper based on the user's browsing history, you can use the goToStep() method:

Use dark colors for code blocksCopy
     
1
2
3
4
5
(async () => {
  await customElements.whenDefined("calcite-stepper");
  const el = await document.querySelector("calcite-stepper").componentOnReady();
  requestAnimationFrame(() => el.goToStep(3));
})();

Events

Calcite Components creates and triggers events using the CustomEvent() constructor.

CustomEvent behaves similarly to Event, which is emitted by HTML elements, such as when clicking a button. For example, you can still access the element in the event payload's target property.

You can view a component's documentation page to determine whether it has any events, such as the calcite-pagination event. For example:

Use dark colors for code blocksCopy
   
1
2
3
document.addEventListener("calcitePaginationChange", event => {
  console.log("Starting item number on the page:", event.target.startItem);
});

Modes

Calcite Components provides light and dark modes, which can be changed using their corresponding CSS classes: calcite-mode-light and calcite-mode-dark. There is also a calcite-mode-auto class which defers to the browser's prefers-color-scheme CSS media query to decide whether the light or dark mode will be used.

Setting the mode class on an element changes all of its child nodes as well. Therefore, to switch the entire application from light to dark, you can do the following:

Use dark colors for code blocksCopy
   
1
2
3
<body class="calcite-mode-dark">
  <!-- Your application content -->
</body>

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.