hide-until-ready

CSS utility attributes for FOUC prevention. Hide custom elements until defined, or show placeholder content that disappears when the component is ready.

Overview

Custom elements go through a brief undefined state before their JavaScript loads and registers them. During this window, the browser renders their raw HTML content, causing a flash of unstyled content (FOUC). The hide-until-ready and show-until-ready attributes solve this with pure CSS — no JavaScript needed.

  • hide-until-ready — hides the element until its custom element is defined
  • show-until-ready — shows the element only while its custom element is undefined (placeholder content)

How It Works

These attributes use the CSS :defined pseudo-class, which matches elements that have been registered via customElements.define(). The CSS rules are simple:

/* How it works — pure CSS, no JavaScript needed */ [hide-until-ready]:not(:defined) { display: none; } [show-until-ready]:defined { display: none; }

Because this is pure CSS evaluated by the browser's style engine, it works immediately — before any JavaScript runs. There is no flicker or timing issue.

The :defined Pseudo-Class

The :defined pseudo-class matches any element that is defined. For custom elements (elements with a hyphen in their tag name), this means customElements.define() has been called for that tag. Standard HTML elements are always :defined.

  • :not(:defined) — matches custom elements before their class is registered
  • :defined — matches custom elements after registration, and all standard HTML elements always

hide-until-ready

Add hide-until-ready to any custom element to prevent it from rendering until its definition is loaded. The element is set to display: none while undefined, then automatically appears once the browser registers the custom element.

<!-- Hidden until the custom element is defined --> <my-component hide-until-ready> Content that should only show when the component is ready. </my-component>

This is the most common use case. It prevents raw, unstyled content from flashing before the component's styles and behavior are applied.

show-until-ready

Add show-until-ready to an element to display it only while the custom element is undefined. Once the element is defined, it disappears. This is useful for loading placeholders, skeleton screens, or fallback content.

<!-- Shown until the custom element is defined, then hidden --> <my-component show-until-ready> Loading placeholder... </my-component> <my-component> Actual component content. </my-component>

The placeholder element uses the same tag name as the real component so that :defined triggers at the right time. When the custom element class is registered, all elements with that tag become :defined simultaneously.

Combined Pattern

Use both attributes together for a smooth loading experience: show a skeleton or placeholder while the component loads, then swap to the real content.

<!-- Loading skeleton shown until component is ready --> <card-wc show-until-ready> <div class="skeleton" style="height: 200px;"></div> </card-wc> <!-- Real component hidden until defined --> <card-wc hide-until-ready> <h3>Card Title</h3> <p>Card content loads without a flash of unstyled markup.</p> </card-wc>

This pattern ensures the user always sees something meaningful — a placeholder while loading, then the real component once ready. No layout shift, no flash of raw markup.

Common Use Cases

Preventing FOUC on Complex Components

Components like dialogs, tab groups, and accordions often render incorrectly before their JavaScript initializes. Use hide-until-ready to avoid showing broken layouts:

<!-- Prevent FOUC on a dialog component --> <dialog-wc hide-until-ready trigger="open-settings"> <h2 slot="heading">Settings</h2> <p>Dialog content here.</p> </dialog-wc> <!-- Prevent layout shift on a tabs component --> <tab-group hide-until-ready> <tab-panel label="First">Panel 1 content</tab-panel> <tab-panel label="Second">Panel 2 content</tab-panel> </tab-group>

Loading Placeholders

For components that may take time to load (charts, maps, heavy widgets), show lightweight placeholder content:

<!-- Show a lightweight placeholder until the heavy component loads --> <chart-wc show-until-ready> <p>Loading chart...</p> </chart-wc> <chart-wc hide-until-ready data-src="/api/chart-data"> <!-- Full chart renders here once the element is defined --> </chart-wc>

Accessibility

  • Content hidden with display: none is removed from the accessibility tree — screen readers will not announce it
  • When the component becomes defined, it appears in the accessibility tree automatically
  • Placeholder content (show-until-ready) is accessible while visible, providing context during loading
  • No JavaScript dependency — if scripts fail to load, hide-until-ready elements stay hidden (graceful degradation), while show-until-ready placeholders remain visible as fallback
  • No ARIA attributes needed — the browser's native rendering handles visibility