Integrating DropInBlog into a Next.js application
This guide explains how to integrate DropInBlog into your Next.js project by adding a custom component.
The integration involves creating a React component that:
Dynamically loads the DropInBlog script to embed blog content on the page.
Enhances navigation by converting DropInBlog links into client-side routes using Next.js’ router.
Observes content changes to apply routing behavior to dynamically inserted blog elements.
Renders a container <div id="dib-posts"></div> where DropInBlog will insert the blog posts.
Create a new file dib-block.tsx in your components directory with the following code:
Be sure to replace the {{blogid}} with what you see on the Code & Layout tab in your admin panel.
Be sure to replace /blog with the correct path if you are not using /blog
Overview
The integration involves creating a React component that:
Dynamically loads the DropInBlog script to embed blog content on the page.
Enhances navigation by converting DropInBlog links into client-side routes using Next.js’ router.
Observes content changes to apply routing behavior to dynamically inserted blog elements.
Renders a container <div id="dib-posts"></div> where DropInBlog will insert the blog posts.
Step-by-Step Instructions
1. Create the DropInBlog component
Create a new file dib-block.tsx in your components directory with the following code:
"use client";
import { useLayoutEffect } from "react";
import { usePathname, useSearchParams, useRouter } from "next/navigation";
/**
* Declare DropInBlog global object on the window for TypeScript
*/
declare global {
interface Window {
dib?: {
reload?: () => void;
[key: string]: any;
};
}
}
/**
* Remove all <script> or <link> tags related to DropInBlog
*/
function removeTags(tag: "link" | "script") {
const tagList =
tag === "script"
? document.querySelectorAll("script[src*='dropinblog']")
: document.querySelectorAll("link[href*='dropinblog']");
tagList.forEach((t) => t.remove());
}
/**
* Create and return the DropInBlog <script> element with an onLoad callback
*/
function createDibScript(onLoad: () => void) {
const script = document.createElement("script");
script.src =
"https://io.dropinblog.com/embedjs/{{blogid}}.js";
script.async = true;
script.onload = onLoad;
return script;
}
/**
* Force DropInBlog to reload content if it's already loaded
*/
function forceDibReload() {
if (window.dib?.reload) {
window.dib.reload();
}
}
/**
* Find all clickable blog elements (both <a> and <div>), and normalize <div> links by extracting href from onclick attribute
*/
function normalizeDivLinks() {
const linksSelector = [
"ul.dib-cat-menu>li >a",
"a.dib-post",
"a.dib-post-back-link",
"a.dib-post-back-link-bottom",
"a.dib-meta-author-link",
"div.dib-related-posts>div.dib-related-post",
"span.dib-meta-item.dib-post-category-text a",
];
const links = document.querySelectorAll(linksSelector.join(", "));
links.forEach((link) => {
if (link instanceof HTMLDivElement) {
// Extract href value from onclick="location.href='...'" and store in data-href
let onclick = link.getAttribute("onclick") ?? "";
onclick = onclick.replace(/location\.href\s*=\s*['"]/, "");
onclick = onclick.replace(/['"]\s*;\s*$/, "");
link.setAttribute("data-href", onclick);
link.removeAttribute("onclick");
}
});
return links;
}
/**
* Add click event listeners to links (both <a> and normalized <div>s) to handle navigation using Next.js router (client-side routing)
*/
function addClickListeners(
links: NodeListOf<Element>,
router: ReturnType<typeof useRouter>
) {
links.forEach((link) => {
link.addEventListener("click", (e) => {
e.preventDefault();
let url: URL | null = null;
if (link instanceof HTMLAnchorElement) {
url = new URL(link.href);
} else if (link instanceof HTMLDivElement) {
const href = link.dataset?.href;
if (href) url = new URL(href, window.location.origin);
}
if (!url) throw new Error("Invalid URL");
const relativePath = url.pathname + url.search;
router.push(relativePath);
});
});
}
/**
* Normalize DropInBlog internal links and override them to use Next.js client-side routing
*/
function overrideLinkClicks(router: ReturnType<typeof useRouter>) {
const links = normalizeDivLinks();
addClickListeners(links, router);
}
/**
* Main component that loads and integrates DropInBlog content into a Next.js page
*/
export default function DibBlock() {
const pathname = usePathname();
const searchParams = useSearchParams();
const router = useRouter();
const searchKey = searchParams.toString();
useLayoutEffect(() => {
if (pathname !== "/blog") return;
const dibContainer = document.getElementById("dib-posts");
if (dibContainer) dibContainer.innerHTML = "";
removeTags("script");
const dibScript = createDibScript(() => {
forceDibReload();
});
document.head.appendChild(dibScript);
const observer = new MutationObserver(() => {
overrideLinkClicks(router);
});
if (dibContainer) {
observer.observe(dibContainer, {
childList: true,
subtree: true,
});
}
return () => {
dibScript.remove();
removeTags("link");
observer.disconnect();
};
}, [pathname, searchKey, router]);
return <div id="dib-posts"></div>;
}
Be sure to replace the {{blogid}} with what you see on the Code & Layout tab in your admin panel.
Be sure to replace /blog with the correct path if you are not using /blog
2. Use the component in a Page
import DibBlock from "@/app/components/dib-block";
export default function Blog() {
return (
<DibBlock />
);
}
Updated on: 19/06/2025