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:
::details-content— style the expanded body of<details>as if it were a part. Shipped in Chrome 131.- Customizable
<select>— pseudos like::picker(select)and::picker-icon. Shipped Chrome 135.
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)");