CSS :defined Pseudo-Class
The CSS :defined pseudo-class selects elements that have been defined by the browser. It matches all standard HTML elements and custom elements that have been successfully registered with JavaScript. It is particularly useful for controlling how custom elements appear before and after their definitions become available.
:defined Syntax
:defined {
property: value;
}
The :defined pseudo-class has no arguments. It can be combined with an element selector to target defined elements of a particular type.
Example Syntax
my-component:defined {
border: 2px solid #0088cc;
}
This rule adds a blue border to <my-component> elements after the custom element has been successfully registered.
The selector has a specificity of 0-1-0. Combined with the my-component type selector, its specificity becomes 0-1-1.
How :defined Works
Browsers recognize standard HTML elements such as <div>, <p>, and <button> without requiring JavaScript registration. These elements always match :defined.
Custom elements are different. A custom element can appear in the HTML before the browser knows its definition. Until it is successfully registered, it does not match :defined.
When JavaScript registers the custom element using customElements.define(), the browser updates the element's matching state automatically.
Expected Matching Behavior
| Element Condition | Matches :defined? |
|---|---|
| Standard HTML element, such as <p> | Yes |
| Standard HTML form control | Yes |
| Custom element before registration | No |
| Custom element after successful registration | Yes |
| Custom element whose definition has not loaded | No |
| Unknown custom-element name that is never registered | No |
The browser updates the selector automatically when the custom element becomes defined. CSS does not need to be reapplied manually.
Important: A defined custom element is not necessarily finished loading external data or rendering all of its content. The pseudo-class indicates that the element's definition is registered, not that every asynchronous task has completed.
Elements That Match :defined
The :defined pseudo-class can match both built-in HTML elements and registered custom elements.
Element Types
| Element Type | Matching Behavior |
|---|---|
| Standard HTML elements | Always match :defined. |
| Autonomous custom elements | Match after successful registration. |
| Customized built-in elements | Match because their built-in HTML element type is defined. |
| Unregistered custom elements | Do not match :defined. |
Standard HTML Elements
<p>This paragraph is already defined.</p>
<button type="button">Click Me</button>
p:defined {
color: #0088cc;
}
button:defined {
border: 2px solid #0088cc;
}
Both elements match immediately because they are standard HTML elements supported by the browser.
Unregistered Custom Element
<status-card>Waiting for definition...</status-card>
status-card:not(:defined) {
display: block;
padding: 12px;
border: 2px dashed #999;
color: #666;
}
Before <status-card> is registered, the :not(:defined) selector matches it and applies the temporary styling.
:defined and Custom Elements
Custom elements allow developers to create reusable HTML components with their own names and behavior. Autonomous custom element names contain a hyphen, such as status-card or user-profile.
JavaScript registers a custom element with the browser's CustomElementRegistry.
HTML
<status-card>Component ready</status-card>
JavaScript
class StatusCard extends HTMLElement {
connectedCallback() {
this.textContent = "Custom element is defined.";
}
}
customElements.define("status-card", StatusCard);
CSS
status-card {
display: block;
padding: 12px;
}
status-card:not(:defined) {
border: 2px dashed #999;
}
status-card:defined {
border: 2px solid #27ae60;
background-color: #eaf7ee;
}
Before registration, the custom element receives a dashed border. After registration, it receives a solid green border and a light green background.
Registration changes the element's defined state. The browser then applies the matching CSS automatically.
Checking Registration with JavaScript
customElements.whenDefined("status-card").then(() => {
console.log("status-card is now defined");
});
The customElements.whenDefined() method returns a promise that resolves when the specified custom element has been registered.
Use :defined when CSS styling is sufficient. Use whenDefined() when JavaScript must wait for the custom element definition.
Practical Uses
The :defined pseudo-class is most useful when custom elements may appear before their JavaScript definitions have loaded.
Hiding an Undefined Custom Element
user-profile:not(:defined) {
visibility: hidden;
}
user-profile:defined {
visibility: visible;
}
This prevents an unregistered custom element from being visible until its definition becomes available.
The visibility property preserves the element's layout space. If you use display: none, the element is removed from layout until it becomes visible.
Displaying a Loading Placeholder
status-card:not(:defined) {
display: block;
padding: 12px;
border: 2px dashed #999;
color: #666;
}
status-card:defined {
border: 2px solid #27ae60;
color: #155724;
}
These rules provide a visual distinction between an undefined custom element and a registered one.
Styling Multiple Custom Elements
user-profile:defined,
status-card:defined {
border: 2px solid #0088cc;
padding: 12px;
}
The styles apply to each custom element once its definition has been registered.
Preventing a Flash of Unstyled Content
When a custom element's appearance depends on its JavaScript definition, :not(:defined) can help avoid displaying an incomplete component.
custom-panel:not(:defined) {
visibility: hidden;
}
custom-panel:defined {
visibility: visible;
}
However, a defined element may still be loading data or updating its contents. Additional loading-state management may be needed for more complex components.
Best Practices
- Use
:definedto style registered custom elements without manually adding state classes. - Use
:not(:defined)to style or temporarily hide custom elements before registration. - Remember that standard HTML elements always match
:defined. - Do not assume a defined custom element has completed all asynchronous loading or rendering.
- Use
customElements.whenDefined()when JavaScript must wait for registration. - Avoid hiding important content indefinitely if a custom element's JavaScript fails to load.
- Provide useful fallback content when custom elements are essential to the page.
- Test components both before and after registration to confirm their appearance and accessibility.
:defined Example
This example demonstrates how a custom element changes appearance after registration. Click Define Element to register the custom element and apply its :defined styles.
HTML
<div class="defined-demo">
<status-card>Waiting for definition...</status-card>
<button type="button" id="define-button">Define Element</button>
</div>
CSS
.defined-demo status-card {
display: block;
padding: 12px;
margin-bottom: 12px;
}
.defined-demo status-card:not(:defined) {
border: 2px dashed #999;
background-color: #f5f5f5;
color: #666;
}
.defined-demo status-card:defined {
border: 2px solid #27ae60;
background-color: #eaf7ee;
color: #155724;
}
.defined-demo button {
padding: 8px 12px;
cursor: pointer;
}
JavaScript
document.querySelector("#define-button").addEventListener("click", () => {
class StatusCard extends HTMLElement {
connectedCallback() {
this.textContent = "Custom element is now defined!";
}
}
customElements.define("status-card", StatusCard);
document.querySelector("#define-button").disabled = true;
});
Browser Result
Initially, the custom element has a gray dashed border. Click Define Element to register it. The message changes, and the border and background become green.
Browser Support
Baseline: Widely available. The :defined pseudo-class has been supported across major browser engines since January 2020.
It works with standard HTML elements and registered custom elements in modern browsers. Older browsers without custom element support may require a fallback.
For current compatibility information, visit Can I Use? and search for CSS :defined.
Specifications
The :defined pseudo-class is defined in Selectors Level 4, with HTML-specific matching behavior defined in the HTML Living Standard.
