DEV Community

nullmake
nullmake

Posted on

Easy Guide to Improving Search Functionality in DocFx Static Sites with Pagefind

In .NET development, DocFx is an incredibly useful tool for automatically generating API documentation. However, the default built-in search powered by lunr.js can sometimes deliver underwhelming results, leading to a suboptimal user experience.

DocFx issue

In this article, I will show you how to easily replace it and supercharge your documentation's search functionality using Pagefind, a highly performant and lightweight static search engine.

Prerequisites

  • This guide assumes you are using DocFx with the modern template (available in DocFx v2.70+).
  • This implementation utilizes the official Pagefind Component UI.

Step-by-Step Implementation

1. Disable the Default Search

First, disable DocFx's built-in search function by updating your configuration file.

docfx.json

"globalMetadata": {
  "_enableSearch": false
}

Enter fullscreen mode Exit fullscreen mode

2. Create a Custom Template to Inject Pagefind UI

Next, create a custom template file to inject the Pagefind search box into your navigation bar.

template/public/main.js

export default {
    start: () => {
        setupPagefind();
    },
};

function setupPagefind() {
    // Prevent duplicate initialization
    if (document.getElementById("pagefind-modal-container")) {
        return;
    }
    const navContainer = document.querySelector("#navbar");
    if (!navContainer) {
        console.error("#navbar was not found.");
        return;
    }
    // Inject Pagefind UI CSS
    if (!document.querySelector('link[href*="pagefind-component-ui.css"]')) {
        const link = document.createElement("link");
        link.href = "pagefind/pagefind-component-ui.css";
        link.rel = "stylesheet";
        document.head.appendChild(link);
    }
    // Inject Pagefind UI JS
    if (!document.querySelector('script[src*="pagefind-component-ui.js"]')) {
        const script = document.createElement("script");
        script.src = "pagefind/pagefind-component-ui.js";
        script.type = "module";
        document.head.appendChild(script);
    }
    // Create and append the search modal container
    const modalContainer = document.createElement("div");
    modalContainer.id = "pagefind-modal-container";
    modalContainer.className = "d-flex align-items-center order-last";
    modalContainer.innerHTML = `
    <pagefind-config bundle-path="/pagefind/"></pagefind-config>
    <pagefind-modal-trigger></pagefind-modal-trigger>
    <pagefind-modal></pagefind-modal>
    `;
    navContainer.appendChild(modalContainer);
}

Enter fullscreen mode Exit fullscreen mode

Now, update your docfx.json to include your custom template folder. Make sure your custom template is listed after the modern template to properly override it.

docfx.json

"template": [
  "default",
  "modern",
  "template" // <-- Add your custom template folder here
]

Enter fullscreen mode Exit fullscreen mode

3. Build DocFx and Run Pagefind Indexing

Build your DocFx site as usual, then run Pagefind to index the generated static files inside the _site directory.

dotnet docfx build docfx.json
npx -y pagefind --site _site

Enter fullscreen mode Exit fullscreen mode

4. Serve the Site and Test

Run the DocFx local server to open your browser and see the new Pagefind search box in action.

dotnet docfx serve _site --open-browser

Enter fullscreen mode Exit fullscreen mode

before
lunr.js search

after
Pagefind search


⚠️ Important Note for Subdirectory Hosting (e.g., GitHub Pages)

If you host your site in a subdirectory (which is common with GitHub Pages), you must update the bundle-path in your template/public/main.js to match your subdirectory structure.

Example: If your site URL is https://<username>.github.io/<repository-name>/, modify the template code like this:

modalContainer.innerHTML = `
<pagefind-config bundle-path="/{repository-name}/pagefind/"></pagefind-config>
<pagefind-modal-trigger></pagefind-modal-trigger>
<pagefind-modal></pagefind-modal>
`;

Enter fullscreen mode Exit fullscreen mode

Live Demo & Source Code

You can see this integration in action and check out the full repository here:

Happy documenting! If you have any questions or feedback, feel free to leave a comment below.

Top comments (0)