Skip to content

Shadow DOM CSS styling with ::part selector

Overview

This is an experimental shim for the ::part CSS selector as defined here

Basic usage

Component author

Apply PTCS.ShadowPart.ShadowPartMixin to any custom element that should expose parts for CSS styling. For example:

let Custom = class extends PTCS.ShadowPart.ShadowPartMixin(Polymer.Element, [], ['primary','secondary'], ['type']) {}

Add the part attribute to a shadow tree element to make it available for styling. For example:

<template>
  <div>
    <div part="title">{title}</div>
    <div part="body"></div>
  </div>
</template>
(title and body are available for styling)

Use the exportparts or partmap attribute to expose inner parts of the component for styling. For example:

<template>
  <div>
    <x-inner part="inner" exportparts="p1: inner-p1"/>
  </div>
</template>
(inner and inner-p1 are available for styling)

HTML/CSS author

Use the ::part selector inside CSS stylesheet to style parts that are exposed by a component. For example:

x-custom[type=styled]::part(title):hover {
  color: blue;
}

Use the ptcs-custom-css element to include your CSS stylesheet in one of 3 ways:

  • As an inline <style> element:
      <ptcs-custom-css>
        <style>
          x-custom[type=styled]::part(title):hover {
            color: blue;
          }
        </style>
      </ptcs-custom-css>
    
  • As a <link> element:
      <ptcs-custom-css>
        <link rel="stylesheet" type="text/css" href="parts.css">
      </ptcs-custom-css>
    
  • As a Polymer style module:
      <link rel="import" href="parts.html">
      <ptcs-custom-css>
        <style include="parts"></style>
      </ptcs-custom-css>
    

API

Namespace

PTCS.ShadowPart

Methods

Method Argument Type Description
ShadowPartMixin The mixin that is applied to each custom element class
stateAttributes string[] Change attributes used for styling (in addition to "disabled", "variant", "themable")
constClasses string[] Class names to be treated as static (in addition to "ptcs-wrapper" and "widget-...")
constAttributes string[] Attributes to be treated as static (in addition to "part")
queueApplyPartAll Trigger styling of all ShadowPartMixin-derived elements in a tree
container host Shadow container to be styled (use document for main html)
resetPartData Clear cached styling data in a tree. Should be called after one or more
<style> modifications in the tree and before queryApplyPartAll
container host Shadow container to be cleaned (use document for main html)
findStyleRule Returns corresponding rule index inside a <style> element
style HTMLStyleElement <style> element
rule string Rule to find
deleteStyleRule Delete rule from a <style> element
style HTMLStyleElement <style> element
index number Rule index to delete
insertStyleRule Insert rule into a <style> element at specified position
style HTMLStyleElement <style> element
rule string Rule to insert
index number Position to insert (optional, defaults to 0)

Known Issues

  • Works for custom elements that implement the ShadowPartMixin only.
  • Styling for DOM that modifies part or partmap attributes after ready() requires a call to this.queueApplyPart().
  • Styling may be voided by presence of more specific selector for same part name and incompatible host selector. For example:
      x-custom.hover::part(header)[alert] {
        background: red;
      }
      x-custom::part(header) {
        background: green;
      }
    
    May cause background for x-custom::part(header)[alert] be undefined. (Mainly in Safari or for partmapped parts in Chrome and Firefox)
  • On IE/Edge shadow DOM styling may have weaker specificity than other CSS rules defined on the page. To make your rules take a precedence you should add more specificity. For example, you can make your rule stronger if you add the :not(.dummy) selector as many times as you need to overcome other CSS selectors. You can write your rule as:
      x-custom::part(header):not(.dummy):not(.dummy):not(.dummy)
      {
        background: Green; height: 5px;
      }
    

Implementation

  1. The CSS styles are parsed for ::part selectors. These are re-written using CSS custom properties or regular selectors for ShadyCSS.

  2. The element shadowRoot DOM is scanned for elements with part attributes. A new style element is added with rules that match these attributes corresponding to part properties provided as CSS custom properties from the element ancestor.

NOTE:

When the part attribute values are modified inside the element shadow tree, this.queueApplyPart() must be called. This is done automatically only when the element is connected for the first time.