Usage
Modes UI components are just regular HTML elements, or custom elements to be precise. You can use them like any other element. Each component has detailed documentation that describes its full API, including properties, events, methods, and more.
If you’re new to custom elements, often referred to as “web components,” this section will familiarize you with how to use them.
Properties
Many components have properties that can be set using attributes. For example, buttons accept a
size
attribute that maps to the size
property which dictates the button’s size.
<mo-button size="medium">Click me</mo-button>
Some properties are boolean, so they only have true/false values. To activate a boolean property, add the corresponding attribute without a value.
<mo-button disabled>Click me</mo-button>
In rare cases, a property may require an array, an object, or a function. For example, to customize the
color picker’s list of preset swatches, you set the swatches
property to an array of colors.
This can be done with JavaScript.
<mo-color-picker></mo-color-picker> <script> const colorPicker = document.querySelector('mo-color-picker'); colorPicker.swatches = ['red', 'orange', 'yellow', 'green', 'blue', 'purple']; </script>
Note that if you are using the React components, you can simply pass an array as a property as you normally would in React. The example uses JavaScript as vanilla HTML does not allow arrays to be set as an attribute.
Refer to a component’s documentation for a complete list of its properties.
Events
You can listen for standard events such as click
, mouseover
, etc. as you normally
would. In addition, some components emit custom events. These work the same way as standard events, but are
prefixed with mo-
to prevent collisions with standard events and other libraries.
<mo-checkbox>Check me</mo-checkbox> <script> const checkbox = document.querySelector('mo-checkbox'); checkbox.addEventListener('mo-change', event => { console.log(event.target.checked ? 'checked' : 'not checked'); }); </script>
Refer to a component’s documentation for a complete list of its custom events.
If your event listeners are causing unintended side-effects, see the section on event bubbling.
Methods
Some components have methods you can call to trigger various behaviors. For example, you can set focus on a
Modes UI input using the focus()
method.
<mo-input></mo-input> <script> const input = document.querySelector('mo-input'); input.focus(); </script>
Refer to a component’s documentation for a complete list of its methods and their arguments.
Slots
Many components use slots to accept content inside of them. The most common slot is the
default slot, which includes any content inside the component that doesn’t have a
slot
attribute.
For example, a button’s default slot is used to populate its label.
<mo-button>Click me</mo-button>
Some components also have named slots. A named slot can be populated by adding a child element with
the appropriate slot
attribute. Notice how the icon below has the
slot="prefix"
attribute? This tells the component to place the icon into its
prefix
slot.
<mo-button> <mo-icon slot="suffix" name="settings"></mo-icon> Settings </mo-button>
The location of a named slot doesn’t matter. You can put it anywhere inside the component and the browser will move it to the right place automatically!
Refer to a component’s documentation for a complete list of available slots.
Don’t use self-closing tags
Custom elements cannot have self-closing tags. Similar to <script>
and
<textarea>
, you must always include the full closing tag.
<!-- Don't do this --> <mo-input /> <!-- Always do this --> <mo-input></mo-input>
Differences from native elements
You might expect similarly named elements to share the same API as native HTML elements. This is not always the case. Modes UI components are not designed to be one-to-one replacements for their HTML counterparts.
For example, <button>
and <mo-button>
both have a
type
attribute, but it does different things. The former controls whether the button submits a
form and the latter controls the button’s appearance.
Don’t make assumptions about a component’s API! To prevent unexpected behaviors, please take the time to review the documentation and make sure you understand what each attribute, property, method, and event is intended to do.
Waiting for components to load
Web components are registered with JavaScript, so depending on how and when you load Modes UI, you may notice a Flash of Undefined Custom Elements (FOUCE) when the page loads. There are a couple ways to prevent this, both of which are described in the linked article.
One option is to use the
:defined
CSS pseudo-class to “hide” custom elements that haven’t been registered yet. You can scope it to specific
tags or you can hide all undefined custom elements as shown below.
:not(:defined) { visibility: hidden; }
As soon as a custom element is registered, it will immediately appear with all of its styles, effectively
eliminating FOUCE. Note the use of visibility: hidden
instead of display: none
to
reduce shifting as elements are registered. The drawback to this approach is that custom elements can
potentially appear one by one instead of all at the same time.
Another option is to use
customElements.whenDefined()
, which returns a promise that resolves when the specified element gets registered. You’ll probably want to
use it with
Promise.allSettled()
in case an element fails to load for some reason.
A clever way to use this method is to hide the <body>
with opacity: 0
and
add a class that fades it in as soon as all your custom elements are defined.
<style> body { opacity: 0; } body.ready { opacity: 1; transition: 0.25s opacity; } </style> <script type="module"> await Promise.allSettled([ customElements.whenDefined('mo-button'), customElements.whenDefined('mo-card'), customElements.whenDefined('mo-rating') ]); // Button, card, and rating are registered now! Add // the `ready` class so the UI fades in. document.body.classList.add('ready'); </script>
Code completion
VS Code
Modes UI ships with a file called vscode.html-custom-data.json
that can be used to describe its
components to Visual Studio Code. This enables code completion for Modes UI components (also known as “code
hinting” or “IntelliSense”). To enable it, you need to tell VS Code where the file is.
- Install Modes UI locally
- Create a folder called
.vscode
at the root of your project - Create a file inside the folder called
settings.json
- Add the following to the file
{ "html.customData": ["./node_modules/@metsooutotec/modes-web-components/dist/vscode.html-custom-data.json"] }
If settings.json
already exists, simply add the above line to the root of the object. Note that
you may need to restart VS Code for the changes to take affect.
Other editors
Most popular editors support custom code completion with a bit of configuration.
Recommended VS Code extensions
You can find the library recommended VS Code extensions by typing @recommended in the search box in the extensions menu on the left side of the window.
The extensions add project and Lit specific syntax highlighting and formatting to ease development and keep the code clean.
These extensions have pre-existing configuration files in the project (e.g. prettier.config.cjs), so no need to worry about different configurations causing conflicts.