The :defined pseudo-class matches built-in elements and custom elements whose definitions have been registered. A named custom element can exist in the DOM before its JavaScript class loads; it matches :not(:defined) during that interval. Registration does not prove that its data request completed or that every child control is ready.
CSS :defined: preserve content while a custom element upgrades
When to use it
An audit-summary custom element contains a short server-rendered status line before its behavior loads. Give the host a stable block box and border immediately so the page does not jump. After definition, a class added by the component can enhance its internal layout. The CSS below marks the pre-upgrade host with a quieter border, while its text stays visible and readable. Test slow script loading, script failure, and a disabled-script browser. Do not set display: none on the undefined host if it contains the only case status. If a custom element replaces light DOM content during upgrade, that replacement needs its own accessibility and loading review; :defined cannot keep the old content present. Check that a defined component with a pending network request still reports loading in words rather than using this selector as a fake data-ready state. A system font and stable minimum size can reduce visual movement without concealing the fallback.
audit-summary { display: block; min-block-size: 4rem; padding: .8rem; border: 1px solid #6e8792; color: #173441; }
audit-summary:not(:defined) { border-style: dashed; background: #f4f7f8; }
audit-summary:defined { border-color: #315f75; }Cost and verification
Matching this state is inexpensive. The risk is a hidden or misleading pre-upgrade page: if the JavaScript bundle fails, an invisible custom element never becomes useful. Keep the fallback content in the markup and verify it with throttled or blocked scripts. A completed definition only means the browser has registered the element; application state, data, and event listeners may settle later. Avoid a global :not(:defined) rule that catches unrelated future custom tags. Scope the selector to the component you own. Inspect layout shift when the real template replaces the fallback and keep the same broad dimensions where practical.
Common Mistakes
- Do not equate :defined with data loaded.
- Do not hide the only meaningful fallback inside an undefined component.
- Do not style every undefined tag with a page-wide selector.
