CSS Shadow Parts
CSS Shadow Parts allow developers to style CSS properties on an element inside of a shadow tree. This is extremely useful in customizing Ionic Framework Shadow DOM components.
Why Shadow Parts?
Ionic Framework is a distributed set of Web Components. Web Components follow the Shadow DOM specification in order to encapsulate styles and markup.
Ionic Framework components are not all Shadow DOM components. If the component is a Shadow DOM component, there will be a badge in the top right of its component documentation. An example of a Shadow DOM component is the button component.
Shadow DOM is useful for preventing styles from leaking out of components and unintentionally applying to other elements. For example, we assign a .button
class to our ion-button
component. Without Shadow DOM encapsulation, if a user were to set the class .button
on one of their own elements, it would inherit the Ionic Framework button styles. Since ion-button
is a Shadow component, this is not a problem.
However, due to this encapsulation, styles aren’t able to bleed into inner elements of Shadow components either. This means that if a Shadow component renders elements inside of its shadow tree, the inner elements cannot be targeted directly with CSS. Using the ion-select
component as an example, it renders the following markup:
<ion-select>
#shadow-root
<div class="select-text select-placeholder"></div>
<div class="select-icon"></div>
</ion-select>
The placeholder text and icon elements are inside of the #shadow-root
, which means the following CSS will NOT work to style the placeholder:
/* Does NOT work */
ion-select .select-placeholder {
color: blue;
}
So how do we solve this? CSS Shadow Parts!
Shadow Parts Explained
Shadow parts allow developers to style inside a shadow tree, from outside of that shadow tree. In order to do so, the part must be exposed and then it can be styled by using ::part.
Exposing a part
When creating a Shadow DOM component, a part can be added to an element inside of a shadow tree by assigning a part
attribute on the element. This is added to the component in Ionic Framework and requires no action from an end user.
Continuing to use the ion-select
component as an example, the markup is updated to look like the following:
<ion-select>
#shadow-root
<div part="placeholder" class="select-text select-placeholder"></div>
<div part="icon" class="select-icon"></div>
</ion-select>
The above shows two parts: placeholder
and icon
. See the select documentation for all of its parts.
With these parts exposed, the element can now be styled directly using ::part.
How ::part works
The ::part()
pseudo-element allows developers to select elements inside of a shadow tree that have been exposed via a part attribute.
Since we know that ion-select
exposes a placeholder
part for styling the text when there is no value selected, we can customize it in the following way:
ion-select::part(placeholder) {
color: blue;
opacity: 1;
}
Styling using ::part
allows any CSS property that is accepted by that element to be changed.
In addition to being able to target the part, pseudo-elements can be styled without them being explicitly exposed:
ion-select::part(placeholder)::first-letter {
font-size: 22px;
font-weight: 500;
}