demo · v130

foundation for part-like pseudos

The chromestatus entry says this change "provides a more solid foundation for building future CSS pseudo-elements (currently known as part-like pseudo-elements) on top of ::part()." This demo stacks ::part() with ::first-line, ::selection, and :placeholder-shown — chains that were rejected before Chrome 130 — and lists the in-flight features that this unblocks.


    

what this unblocks

The motivation cited on chromestatus: this change clears the way for several "part-like" pseudo-elements that style internals of native elements. Two are already in flight in Chrome:

Both of those features need to compose with other pseudo-classes (:hover, :focus, ::before, ::selection). The Chrome 130 spec relaxation is the load-bearing step that makes the chains parseable.

pre-Chrome 130 (rejected)

my-input::part(field):hover {
  background: var(--bg-stone);        /* OK pre-130 */
}
my-input::part(field)::first-line {
  font-weight: bold;                  /* invalid pre-130 */
}
my-input::part(field):placeholder-shown {
  color: var(--text-muted);           /* invalid pre-130 */
}

Chrome 130+

my-input::part(field):hover {
  background: var(--bg-stone);        /* still OK */
}
my-input::part(field)::first-line {
  font-weight: bold;                  /* now valid */
}
my-input::part(field):placeholder-shown {
  color: var(--text-muted);           /* now valid */
}
/* combinators still NOT allowed: */
/* my-input::part(field) > .x — rejected */
/* my-input::part(field):has(.x) — rejected */
/* my-input::part(field)::part(icon) — rejected */

the code

// custom element exposes a real <input> via part="input"
class FieldRow extends HTMLElement {
  connectedCallback() {
    this.attachShadow({ mode: "open" }).innerHTML = `
      <input id="foundation-input" name="foundation-input" part="input" placeholder="type here...">
      <p part="text">Lorem ipsum dolor sit amet, the first line will
      be styled with first-line if enabled above.</p>`;
  }
}
customElements.define("field-row", FieldRow);

// Chrome 130 unblocks chained pseudos after ::part()
const supported = CSS.supports("selector(::part(x):placeholder-shown)");

see also