0

I have an HTML custom element that inherits from HTMLElement. The template contains:

<input type="text" part="input"/>

Sample CSS:

  my-element::part(input) {
    padding-right: 1px;
  }

Sample JavaScript (inside class MyElement {}):

  this.input.style.paddingRight = "25px";

The Style inspector in DevTools (Rules in Firefox) crosses out the ::part declaration for padding-right and shows:

  element.style {
    padding-right:25px;
  }

But the computed value inspector shows padding-right:1px and it's rendered as 1px.

The JS code is running after the page fully loads. I don't see a straightforward way around this behavior. If I modify a CSS property for this element in JS, then I cannot declare it CSS. At least not with padding.

Why does a pseudo-element of the custom element take precedence over the element's own style?

The fact that the Style/Rules inspector disagrees with the Computed inspector makes me think this is a bug in both browsers, but I'm no expert. I have not yet tried this on browserstack to check other platforms. Right now I'm focused on working around this unexpected behavior.

It's a bit of work to create a working demo snippet, and the behavior is the same across Firefox and Chrome in Win11, so I'll wait until someone requests it.

6
  • I need to check the specs, but iirc the idea of ::part is to allow to overwrite the style of the custom element; you add a basic style to your elements but expose elements with part so that the user of the component can change the style. Due to that it has a higher specificity. Commented Oct 9, 2024 at 17:34
  • If I modify a CSS property for this element in JS, then I cannot declare it CSS. At least not with padding. what do you mean with that? Commented Oct 9, 2024 at 17:36
  • @t.niese - I mean what my hypothetical example illustrates, and what the accepted answer here details: Styling this in CSS with ::part takes precedence over modifying the value in JavaScript with input.style. To me this was a surprise because it's the first time I've seen a CSS rule override element.style. Not even CSS #id does that. important solves it, thankfully. Commented Oct 9, 2024 at 17:42
  • 1
    For reference: github.com/WICG/webcomponents/issues/847 Commented Oct 10, 2024 at 11:16
  • @Kaiido - given the agreement on the spec, the part that seems like a bug to me is the display in the DevTools inspectors. Commented Oct 10, 2024 at 12:35

3 Answers 3

2

The ::part pseudo-element works in conjunction with browser rendering layers and the cascade order of styles. To fix this you can force higher specificity in JavaScript code:

this.input.style.setProperty('padding-right', '25px', 'important');

This code will ensure that the inline style with !important takes precedence over the ::part pseudo-element styles.

Sign up to request clarification or add additional context in comments.

2 Comments

Great. My only issue is trivial: I was using Object.assign() to assign a block of CSS properties, now I can't do that. Thanks for the prompt reply.
fyi - I see you're new here. You can format code using Markdown. Here are the local docs: stackoverflow.com/editing-help
0

Here's a workaround for the issue as it relates to font properties. It avoids ::part and thus !important, which @Danny'365CSI'Engelman deemed a "red flag".

Setting all of the shadow DOM <input> (the ::part element)'s CSS font properties to inherit allows me to set those properties for the custom element itself, not the ::part. If you have multiple shadow DOM elements with different font settings then this is not possible, but how often does that happen?

<template id="my-template">
  <style>
    input {
      font:inherit;
      font-kerning:inherit;
      font-size-adjust:inherit;
      font-synthesis:inherit;
      font-optical-sizing:inherit;
      font-palette:inherit;
    }
    ...

AFAICT that's all the CSS font properties that are not "experimental" or quasi-deprecated (like font-feature-settings). No more ::part or !important for fonts.

This solution might work for other non-layout properties. For example, it doesn't work for padding because it doubles the amount of padding by applying it to both the DOM and shadow DOM elements.

Comments

-1

I can't replicate your findings, there must be something else in your code

Needing !important is almost always a red flag for CSS issues

<style>
  my-element::part(input){
    background: green;
  }
  my-element::part(input2){
    padding-right: 1px;
  }
</style>
<my-element>
  <template shadowrootmode="open">
    <style>
      input{
        padding-right:25px;
      }
      span{
        background:pink
      }
    </style>
    <input part="input input1"><span>25px padding-right after input1</span>
    <br>
    <input part="input input2"><span>1px padding-right after input2</span>
  </template>
</my-element>

input1:

input2

3 Comments

They're using inline style, you're not.
ah yes, tnx, in HTML inline styles overrule CSS styles. (and in SVG the other way round)
Nope, same in svg, you're confusing with presentation attributes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.