Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
This fallback CSS assumes a web component that contains a <noscript> fallback,
as well as author-supplied content, and separately has a script to swap the
<noscript> with `<div class="fallback">` if JS is enabled, but the web component
definition is not defined.

Ex.

<cfpb-example-btn hasfallback>
<!-- author-supplied no-js fallback -->
<noscript><button>Click this basic button!</button>

<!-- author-supplied slotted content -->
Click this fancy button!
</cfpb-example-btn>
*/

/* 1. If JS is disabled, hide everything except <noscript> */
[hasfallback] > :not(noscript) {
display: none;
}

/* 2. If JS is enabled, but web component definition is not defined, show fallback. */
[hasfallback] > .fallback {
display: block;
}

/* 3. If JS is enabled and web component definition is defined, operate as normal. */
[hasfallback]:defined > :not(noscript) {
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
(function () {
function applyFallback(el) {
if (!el) return;

const tag = el.tagName.toLowerCase();
const isDefined = !!customElements.get(tag);
const noscript = el.querySelector('noscript');

// Only act if the element is NOT defined and there is a <noscript>
if (!isDefined && noscript) {
// Create a <div> with the fallback content.
const fallbackDiv = document.createElement('div');
fallbackDiv.className = 'fallback';
fallbackDiv.innerHTML = noscript.innerHTML;

// Insert fallback at the top.
el.insertBefore(fallbackDiv, el.firstChild);

// Hide the original <noscript> to avoid duplicates.
noscript.style.display = 'none';

/*
// Hide other non-fallback children (optional; fallback.css handles this).
Array.from(el.children).forEach((child) => {
if (child !== fallbackDiv && child !== noscript) {
child.style.display = 'none';
}
});
*/
}
}

function applyAllFallbacks(selector = '[fallback]') {
document.querySelectorAll(selector).forEach((el) => applyFallback(el));
}

// Web Component support detection.
const supportsWC =
'customElements' in window &&
'attachShadow' in Element.prototype &&
'content' in document.createElement('template');

// Only apply fallback globally if web components are NOT supported.
if (!supportsWC) {
document.addEventListener('DOMContentLoaded', applyAllFallbacks);
}
})();