1. Introduction
1.1. Motivation
Build-in elements provided by user agents have certain “states” that can change over time depending on user interaction and other factors, and are exposed to web authors through pseudo classes. For example, some form controls have the “invalid” state, which is exposed through the :invalid pseudo-class.
Like built-in elements, custom elements can have various states to be in too, and custom element authors want to expose these states in a similar fashion as the built-in elements.
1.2. Solution
This specification defines an API to inform custom element's states to the
user agent, and a pseudo-class to select elements with specific states.
The former is the states
IDL attribute of ElementInternals
, and the latter is the custom state pseudo class.
Assume that LabeledCheckbox
doesn’t expose its "checked" state
via a content attribute.
<!DOCTYPE html> < body > <!-- Basic usage: --> < script > class LabeledCheckboxextends HTMLElement{ constructor() { super (); this . _internals= this . attachInternals(); this . addEventListener( 'click' , this . _onClick. bind( this )); const shadowRoot= this . attachShadow({ mode: 'closed' }); shadowRoot. innerHTML= `<style> :host::before { content: '[ ]'; white-space: pre; font-family: monospace; } :host(:--checked)::before { content: '[x]' } </style> <slot>Label</slot>` ; } get checked() { return this . _internals. states. has( '--checked' ); } set checked( flag) { if ( flag) this . _internals. states. add( '--checked' ); else this . _internals. states. delete ( '--checked' ); } _onClick( event) { this . checked= ! this . checked; } } customElements. define( 'labeled-checkbox' , LabeledCheckbox); </ script > < style > labeled-checkbox { border : dashed red ; } labeled-checkbox : --checked { border : solid ; } </ style > < labeled-checkbox > You need to check this</ labeled-checkbox > < script > class QuestionBoxextends HTMLElement{ constructor() { super (); const shadowRoot= this . attachShadow({ mode: 'closed' }); shadowRoot. innerHTML= `<div><slot>Question</slot></div> <labeled-checkbox part='checkbox'>Yes</labeled-checkbox>` ; } } customElements. define( 'question-box' , QuestionBox); </ script > < style > question-box :: part ( checkbox ) { color : red ; } question-box :: part ( checkbox ) : --checked { color : green ; } </ style > < question-box > Continue?</ question-box > </ body >
2. Exposing custom element states
Each autonomous custom element has states set, a set of strings, and the the custom element is initially associated with an empty set of strings.
Support customized built-in elements. <https://github.com/whatwg/html/issues/5166>
partial interface ElementInternals {readonly attribute CustomStateSet ; }; [
states Exposed =Window ]interface {
CustomStateSet setlike <DOMString >;undefined add (DOMString ); };
value
The states
IDL attribute returns the states set of this’s target element.
The add(value)
method, when invoked, must run these steps:
-
If value does not match to <dashed-ident>, then throw a "
SyntaxError
"DOMException
. -
Invoke the default
add
operation, which thesetlike<DOMString>
would have ifCustomStateSet
interface had noadd(value)
operation, with value arguemnt.
readyState
with "loading"
, "interactive"
, and "complete"
values can be mapped to three exclusive boolean states, "--loading"
, "--interactive"
, and "--complete"
.
// Change the readyState from anything to "complete". this . _readyState= "complete" ; this . _internals. states
. delete ( "--loading" ); this . _internals. states
. delete ( "--interactive" ); this . _internals. states
. add
( "--complete" );
Support non-boolean states. <https://github.com/WICG/custom-state-pseudo-class/issues/4>
3. Selecting a custom element with a specific state
The custom state pseudo class :--foo is a pseudo-class, and applies while an element has a certain state. "State" is a per-element information which can change over time depending on user interaction and other extrinsic factors. The custom state pseudo class must start with :, followed by one <dashed-ident>, otherwise the selector is invalid.
The custom state pseudo class must match any element that is an autonomous custom element and whose states set contains the specified <dashed-ident>.