Customizing
The design tokens should not be customized as they are maintained by Metso and must remain consistent with the brand. Users can customize components at a lower level but they should still remain consistent with the branding.
Component parts
Whereas design tokens offer a high-level way to customize the library, component parts offer a low-level way to customize individual components. Again, this is done with pure CSS — no preprocessor required.
Modes UI components use a
shadow DOM
to encapsulate their styles and behaviors. As a result, you can’t simply target their internals with the
usual CSS selectors. Instead, components expose “parts” that can be targeted with the
CSS part selector, or ::part()
.
Here’s an example that modifies buttons with the tomato-button
class.
<mo-button class="tomato-button"> Tomato Button </mo-button> <style> .tomato-button::part(base) { background: var(--color-docs-background); border: solid 1px tomato; } .tomato-button::part(base):hover { background: rgba(255, 99, 71, 0.1); } .tomato-button::part(base):active { background: rgba(255, 99, 71, 0.2); } .tomato-button::part(base):focus-visible { box-shadow: 0 0 0 3px rgba(255, 99, 71, 0.33); } .tomato-button::part(label) { color: tomato; } </style>
Note that you must ensure that your custom CSS changes still align with Metso’s branding.
At first glance, this approach might seem a bit verbose or even limiting, but it comes with a few important advantages:
-
Customizations can be made to components with explicit selectors, such as
::part(icon)
, rather than implicit selectors, such as.button > div > span + .icon
, that are much more fragile. -
The internal structure of a component will likely change as it evolves. By exposing component parts through an API, the internals can be reworked without fear of breaking customizations as long as its parts remain intact.
-
It encourages us to think more about how components are designed and how customizations should be allowed before users can take advantage of them. Once we opt a part into the component’s API, it’s guaranteed to be supported and can’t be removed until a major version of the library is released.
Most (but not all) components expose parts. You can find them in each component’s API documentation under the “CSS Parts” section.
Custom properties
For convenience, some components expose CSS custom properties you can override. These are not design tokens,
nor do they have the same --mo-
prefix since they’re scoped to a component.
You can set custom properties on a component in your stylesheet.
mo-avatar { --size: 6rem; }
This will also work if you need to target a subset of components with a specific class.
mo-avatar.your-class { --size: 6rem; }
Alternatively, you can set them inline directly on the element.
<mo-avatar style="--size: 6rem;"></mo-avatar>
Not all components expose CSS custom properties. For those that do, they can be found in the component’s API documentation.
Animations
Some components use animation, such as when a dialog is shown or hidden. Animations are performed using the Web Animations API rather than CSS. However, you can still customize them through Modes UI’s animation registry. If a component has customizable animations, they’ll be listed in the “Animation” section of its documentation.
To customize a default animation, use the setDefaultAnimation()
method. The function accepts an
animation name (found in the component’s docs) and an object with keyframes
and
options
or null
to disable the animation.
This example will make all dialogs use a custom show animation.
import { setDefaultAnimation } from 'modes-web-components/dist/utilities/animation-registry.js'; // Change the default animation for all dialogs setDefaultAnimation('dialog.show', { keyframes: [ { transform: 'rotate(-10deg) scale(0.5)', opacity: '0' }, { transform: 'rotate(0deg) scale(1)', opacity: '1' } ], options: { duration: 500 } });
If you only want to target a single component, use the setAnimation()
method instead. This
function accepts an element, an animation name, and an object comprised of animation
keyframes
and options
.
In this example, only the target dialog will use a custom show animation.
import { setAnimation } from 'modes-web-components/dist/utilities/animation-registry.js'; // Change the animation for a single dialog const dialog = document.querySelector('#my-dialog'); setAnimation(dialog, 'dialog.show', { keyframes: [ { transform: 'rotate(-10deg) scale(0.5)', opacity: '0' }, { transform: 'rotate(0deg) scale(1)', opacity: '1' } ], options: { duration: 500 } });
To learn more about creating Web Animations, refer to the documentation for
Element.animate()
.
Animations respect the users prefers-reduced-motion
setting. When this setting is enabled,
animations will not be played. To disable animations for all users, pass in null
instead of a
keyframes/options object.