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:
<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:
<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:
<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.
calcite-notice {
--calcite-color-foreground-1: #151515;
--calcite-color-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
attribute is added to components once they are hydrated, and is useful when debugging your application.
When defined
The when
method of the custom
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:
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 component
method. The method returns a Promise that resolves after the component
lifecycle method fires. It is useful for making sure a component is loaded before using its methods, or when one component is dependent on another.
For example, you may want to display calcite-loader
until other component(s) finish rendering:
(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 request
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 go
method:
(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 Custom
constructor.
Custom
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:
document.addEventListener("calcitePaginationChange", event => {
console.log(`Starting item number on the page: ${event.target.startItem}`);
});
Global configuration
Version
Since 2.10
, developers can use the calcite
global variable to detect the Calcite version at runtime.
window.addEventListener("load", () => console.log(window.calciteConfig.version));
Log messages
Since 2.11
, key messages are logged to the console, such as component deprecations. Developers can opt to remove messaging from production environments and builds using calcite
:
var calciteConfig = {
logLevel: "off"
};
Forms
Each component within a form must be populated with a name
attribute in order to pass the value
properly on form submission. For instance, adding name
attributes to Input Date Picker and Text Area:
<form>
<calcite-label>
Observation date:
<calcite-input-date-picker name="observation-date"></calcite-input-date-picker>
</calcite-label>
<calcite-label>
Observation notes:
<calcite-text-area name="observation-notes" placeholder="Observation notes" max-length="250"></calcite-text-area>
</calcite-label>
<calcite-button type="submit">Submit</calcite-button>
</form>
For additional considerations with forms, explore accessibility with forms.
Form validation
Form validation includes the use of the status
, validation
, and validation
properties. The properties support default and custom validation messages and icons when a component's status
property is "invalid"
.
Validation constraints
To set up custom constraints:
-
Create a validation constraints array to define custom constraints, messages, and icons for specific fields using their
id
. -
Utilize a function like
set
to set theCustom Validity validation
,Message validation
, andIcon status
on the respective fields. -
Use an event listener to check the user input against the predefined validation constraints. If the user input does not meet the specified constraints, a custom validation message is set using the
set
function.Custom Validity
Patterns
The use of the pattern
attribute can support constraints used for form validation. When used, it defines a regular expression that the input value must match in order for the form to be considered valid. For instance, defining validation
s and validation
s that will be displayed when a specified part of the pattern
is matched.
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:
<body class="calcite-mode-dark">
<!-- Your application content -->
</body>