Skip to content

Commit 36cdefc

Browse files
Add global wc-fallback script and styles
1 parent 658a68e commit 36cdefc

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(function () {
2+
function applyFallback(el) {
3+
if (!el) return;
4+
5+
const tag = el.tagName.toLowerCase();
6+
const isDefined = !!customElements.get(tag);
7+
const noscript = el.querySelector('noscript');
8+
9+
// Only act if the element is NOT defined and there is a <noscript>
10+
if (!isDefined && noscript) {
11+
// Create a <div> with the fallback content.
12+
const fallbackDiv = document.createElement('div');
13+
fallbackDiv.className = 'fallback';
14+
fallbackDiv.innerHTML = noscript.innerHTML;
15+
16+
// Insert fallback at the top.
17+
el.insertBefore(fallbackDiv, el.firstChild);
18+
19+
// Hide the original <noscript> to avoid duplicates.
20+
noscript.style.display = 'none';
21+
22+
/*
23+
// Hide other non-fallback children (optional; fallback.css handles this).
24+
Array.from(el.children).forEach((child) => {
25+
if (child !== fallbackDiv && child !== noscript) {
26+
child.style.display = 'none';
27+
}
28+
});
29+
`` */
30+
}
31+
}
32+
33+
function applyAllFallbacks(selector = '[fallback]') {
34+
document.querySelectorAll(selector).forEach((el) => applyFallback(el));
35+
}
36+
37+
// Web Component support detection.
38+
const supportsWC =
39+
'customElements' in window &&
40+
'attachShadow' in Element.prototype &&
41+
'content' in document.createElement('template');
42+
43+
// Only apply fallback globally if web components are NOT supported.
44+
if (!supportsWC) {
45+
document.addEventListener('DOMContentLoaded', applyAllFallbacks);
46+
}
47+
})();
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
This fallback CSS assumes a web component that contains a <noscript> fallback,
3+
as well as author-supplied content, and separately has a script to swap the
4+
<noscript> with `<div class="fallback">` if JS is enabled, but the web component
5+
definition is not defined.
6+
7+
Ex.
8+
9+
<cfpb-example-btn hasfallback>
10+
<!-- author-supplied no-js fallback -->
11+
<noscript><button>Click this basic button!</button>
12+
13+
<!-- author-supplied slotted content -->
14+
Click this fancy button!
15+
</cfpb-example-btn>
16+
*/
17+
18+
/* 1. If JS is disabled, hide everything except <noscript> */
19+
[hasfallback] > :not(noscript) {
20+
display: none;
21+
}
22+
23+
/* 2. If JS is enabled, but web component definition is not defined, show fallback. */
24+
[hasfallback] > .fallback {
25+
display: block;
26+
}
27+
28+
/* 3. If JS is enabled and web component definition is defined, operate as normal. */
29+
[hasfallback]:defined > :not(noscript) {
30+
display: block;
31+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(function () {
2+
function applyFallback(el) {
3+
if (!el) return;
4+
5+
const tag = el.tagName.toLowerCase();
6+
const isDefined = !!customElements.get(tag);
7+
const noscript = el.querySelector('noscript');
8+
9+
// Only act if the element is NOT defined and there is a <noscript>
10+
if (!isDefined && noscript) {
11+
// Create a <div> with the fallback content.
12+
const fallbackDiv = document.createElement('div');
13+
fallbackDiv.className = 'fallback';
14+
fallbackDiv.innerHTML = noscript.innerHTML;
15+
16+
// Insert fallback at the top.
17+
el.insertBefore(fallbackDiv, el.firstChild);
18+
19+
// Hide the original <noscript> to avoid duplicates.
20+
noscript.style.display = 'none';
21+
22+
/*
23+
// Hide other non-fallback children (optional; fallback.css handles this).
24+
Array.from(el.children).forEach((child) => {
25+
if (child !== fallbackDiv && child !== noscript) {
26+
child.style.display = 'none';
27+
}
28+
});
29+
*/
30+
}
31+
}
32+
33+
function applyAllFallbacks(selector = '[fallback]') {
34+
document.querySelectorAll(selector).forEach((el) => applyFallback(el));
35+
}
36+
37+
// Web Component support detection.
38+
const supportsWC =
39+
'customElements' in window &&
40+
'attachShadow' in Element.prototype &&
41+
'content' in document.createElement('template');
42+
43+
// Only apply fallback globally if web components are NOT supported.
44+
if (!supportsWC) {
45+
document.addEventListener('DOMContentLoaded', applyAllFallbacks);
46+
}
47+
})();

0 commit comments

Comments
 (0)