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;
}
Parts work with most pseudo-classes , as well:
ion-item::part(native):hover {
color: green;
}
There are some known limitations with vendor prefixed pseudo-elements and structural pseudo-classes .
Ionic Framework Parts
All exposed parts for an Ionic Framework component can be found under the CSS Shadow Parts heading on its API page. To view all components and their API pages, see the Component documentation .
In order to have parts a component must meet the following criteria:
ion-card-header
is a Shadow component, but all styles are applied to the host element. Since it has no child elements, there’s no need for parts.
ion-title
, the child element is a structural element used to position the inner elements. We do not recommend customizing structural elements as this can have unexpected results.
We welcome recommendations for additional parts. Please create a new GitHub issue with as much information as possible when requesting a part.
Known Limitations
Browser Support
CSS Shadow Parts are supported in the recent versions of all of the major browsers. However, some of the older versions do not support shadow parts. Verify the browser support meets the requirements before implementing parts in an app. If browser support for older versions is required, we recommend continuing to use CSS Variables for styling.
Vendor Prefixed Pseudo-Elements
pseudo-elements are not supported at this time. An example of this would be any of the
::-webkit-scrollbar
pseudo-elements:
/* Does NOT work */
my-component::part(scroll)::-webkit-scrollbar {
background: green;
}
See this issue on GitHub for more information.
Structural Pseudo-Classes
Most pseudo-classes are supported with parts, however, structural pseudo-classes are not. An example of structural pseudo-classes that do not work is below.
/* Does NOT work */
my-component::part(container):first-child {
background: green;
}
/* Does NOT work */
my-component::part(container):last-child {
background: green;
}