, 2 min read
Lazy Loading of Pagefind
This blog uses Pagefind to provide search on this website.
I had written on this here: Pagefind: Searching in Static Sites.
In a first step I already removed the ca. 118 kB large pagefind-ui.js.
Now I have gone full lazy-loading.
I have added this to my CSS. The highlighted lines are changed to what Grok in a conversation had proposed.
#search-placeholder {
height: calc(56px * var(--pagefind-ui-scale));
padding: 0 calc(70px * var(--pagefind-ui-scale)) 0 calc(54px * var(--pagefind-ui-scale));
background-color: var(--pagefind-ui-background);
border: var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);
border-radius: var(--pagefind-ui-border-radius);
font-size: calc(17px * var(--pagefind-ui-scale));
font-weight: 500;
font-family: var(--pagefind-ui-font);
color: var(--pagefind-ui-text);
width: 100%;
box-sizing: border-box;
appearance: none;
-webkit-appearance: none;
}
#search-placeholder::placeholder { opacity: 0.2; color: var(--pagefind-ui-text); }
#search-wrapper { position: relative; }
#search-wrapper::before {
content: "";
position: absolute;
top: 50%;
left: calc(20px * var(--pagefind-ui-scale));
transform: translateY(-50%);
width: calc(18px * var(--pagefind-ui-scale));
height: calc(18px * var(--pagefind-ui-scale));
background-color: var(--pagefind-ui-text);
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") center / contain no-repeat;
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") center / contain no-repeat;
pointer-events: none;
z-index: 1;
}
The HTML and JavaScript look like this.
<div id="search">
<div id="search-wrapper">
<input type="search"
id="search-placeholder"
class="pagefind-ui__search-input"
placeholder="Search"
autocomplete="off"
autocapitalize="none"
enterkeyhint="search">
</div>
</div>
<script>
let pfLoaded = false;
function loadPagefindUI() {
if (pfLoaded) return;
pfLoaded = true;
const link = document.createElement("link"); // 1. Load the CSS dynamically
link.rel = "stylesheet";
link.href = "/pagefind/pagefind-ui.css";
document.head.appendChild(link);
const script = document.createElement("script"); // Load the JS
script.src = "/pagefind/pagefind-ui.js";
script.onload = () => {
const container = document.getElementById("search");
container.innerHTML = ""; // this removes the placeholder
new PagefindUI({ element: "#search", showSubResults: true, autofocus: true });
};
document.head.appendChild(script);
}
document.addEventListener("DOMContentLoaded", () => {
const placeholder = document.getElementById("search-placeholder");
if (placeholder) {
placeholder.addEventListener("focus", loadPagefindUI, { once: true });
placeholder.addEventListener("click", loadPagefindUI, { once: true });
}
});
</script>
With these changes neither pagefind-ui.css nor pagefind-ui.js are loaded unless the visitor clicks into the search form.
This helped to achieve 0 ms total blocking time, and 0.037 ms cumulative layout shift in PageSpeed Insights.