Re: [csswg-drafts] [selectors] Declarative custom `:state()` states (#12502)

@seanmay I use the _existing_ [CSS Custom State](https://developer.mozilla.org/en-US/docs/Web/CSS/:state) to create CSS APIs for custom elements that are akin to `:checked`, `:open`, `:popover-open`, `:focus`, `:hover`, `:active`, `:playing`, `:invalid`, `:required`, `:disabled` for built-in elements. In any of those cases, having something within CSS override them would be inappropriate and it would be for custom elements as well, which is why I’m suggesting that this might be outside of the purview of CSS. That’s not to say one can’t use CSS Custom State to create selectors for custom elements that’d be like the built-in `:any-link` or `:heading`, but to me it seems a little misplaced to do so using something for _state._

- - -

Imagine I have an existing custom element that has shadow styles for `:state(open)` which it sets when `ariaExpanded` has been set for its `ElementInternals`. As the custom element author, I’m deciding when that state gets added. If document authors can set states, then they could trigger those styles when they shouldn’t apply. I’m not sure if this is covered by the “Detailed discussion” of the proposal.

<details><summary>Code example of the above</summary>

```html
<!-- CE definition that’s controlling its state -->
<script>
customElements.define("my-element", class extends HTMLElement {
  #internals = this.attachInternals();

  get open() {
    return this.#internals.states.has("open");
  }

  set open(value) {
    if (value === true) {
      this.#internals.ariaExpanded = "true";
      this.#internals.states.add("open");
    } else if (value === false) {
      this.#internals.ariaExpanded = "false";
      this.#internals.states.delete("open");
    }
  }

  constructor() {
    super();
    // Ignore the fact that there’s no ARIA role… trying to keep this focused.

    // Default expanded state is false, so `open` does not apply
    this.#internals.ariaExpanded = "false";

    this.attachShadow({ mode: "open" });

    this.shadowRoot.innerHTML = `<slot></slot><style>
      :host(:state(open)) {
        /* Open styles */
      }
    </style>`;

    this.addEventListener("click", () => {
      this.open = !this.open;
    });
  }
});
</script>

<style>
@state open {
  matches: my-element;
}
</style>

<my-element>Open styles apply when they shouldn’t</my-element>
```

</details>

-- 
GitHub Notification of comment by knowler
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12502#issuecomment-3091469730 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Saturday, 19 July 2025 03:37:54 UTC