For more than a decade, creating or customizing a Blogger theme has been a frustrating experience. Developers have had to manually write and edit massive, monolithic XML files that combine HTML, CSS, native template loops, conditional tags, and inline scripts in a single unmanageable file. What if you could build modern, production-ready Blogger layouts using clean, modular React components, typed with TypeScript, styled with Tailwind CSS, and compiled automatically with hot-reloading? Introducing @antinna/blogger-theme—an innovative, type-safe development framework that changes Blogger development forever by compiling React and JSX directly into native Blogger-compliant XML templates.
The latest version of @antinna/blogger-theme has undergone major enhancements. It now fully supports native typings out of the box. You no longer need to write complex local .d.ts files to declare Blogger namespaces. The framework directly exports typed layout components (like BSection, BWidget, BLoop, BIf, and BClientScript) that typecheck perfectly with TypeScript automatically!
📖 Quick Navigation
- 1. The Problem with Legacy Blogger XML Files
- 2. Introducing @antinna/blogger-theme: Core Concepts
- 3. Understanding the JSX Compiler and Core Exports
- 4. Step-by-Step Theme Building with TypeScript
- 5. Integrating an Embedded React App with BClientScript
- 6. Styling with Tailwind CSS and Building the Pipeline
- 7. Quickstart Template Repository and Installation
- 8. Benefits of this Modern Approach
- 9. Conclusion & Next Steps
Step 1 The Problem with Legacy Blogger XML Files
Traditional Blogger layouts are structured inside a single, complex XML document. This monolithic approach forces you to combine server-side layout logic, page configurations, global styles, and client scripts into one file. Development quickly becomes difficult because:
- No Module Separation: You cannot break your header, sidebar, post layout, or comments section into clean, reusable files.
- No Type-Safety or Autocomplete: Editors have no understanding of Blogger's proprietary template attributes, resulting in frequent syntax issues and typos.
- Fragile Script Injections: Adding custom client JavaScript requires either confusing CDATA blocks or writing unreadable, HTML-escaped character strings.
Step 2 Introducing @antinna/blogger-theme: Core Concepts
The @antinna/blogger-theme framework completely changes how you build Blogger themes. It compiles modern, component-driven React JSX templates into the exact XML tags that Blogger's template engine requires. It handles complex operations automatically:
- Translates JSX components into compliant
<b:section>,<b:widget>, and<b:includable>XML blocks. - Enforces strict type-safety for conditional constructs (
<BIf>) and server loops (<BLoop>). - Injects bundled CSS sheets and single-page React apps safely into Blogger's CDATA blocks.
Step 3 Understanding the JSX Compiler and Core Exports
The framework exports a comprehensive suite of typed JSX components that align directly with Blogger's layout tags. This removes the need to write custom TypeScript declarations. Key exports include:
| Exported Component | Blogger XML Target | Key Attributes / Features |
|---|---|---|
BloggerTheme |
Theme Orchestrator | Takes document headers, body layouts, and builds the raw theme string. |
BSection |
<b:section> |
A layout container representing a sidebar, header, or post grid area. |
BWidget |
<b:widget> |
Represents specific widget assets (like a Header, Blog, or AdSense block). |
BIf |
<b:if> |
Enforces conditional structures (e.g. testing if the page is a homepage). |
BLoop |
<b:loop> |
Loops through data arrays like "data:posts". |
BClientScript |
Script CDATA Injection | Compiles and embeds external TypeScript/JavaScript app scripts. |
Step 4 Step-by-Step Theme Building with TypeScript
To compile your theme, create a central script file (e.g. theme/src/main.tsx). This script acts as the entry point, defining your layouts and calling the compiler to generate the XML theme file:
import * as fs from "fs";
import * as path from "path";
import { fileURLToPath } from "node:url";
import {
BloggerTheme,
BSection,
BWidget,
BClientScript,
BSkin,
Title,
BIf,
BIncludable,
BInclude,
BLoop,
BData,
BEval,
} from "@antinna/blogger-theme";
// Polyfill __dirname for ES Modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const ROOT_DIR = path.resolve(__dirname, "../../");
const DIST_DIR = path.resolve(ROOT_DIR, "dist");
const OUTPUT_CSS_PATH = path.resolve(DIST_DIR, "output.css");
const REACT_APP_ENTRY = path.resolve(ROOT_DIR, "app/src/index.tsx");
const BlogHeader = () => (
<header className="header-container">
<BSection
id="main-header"
className="main-header-sec"
maxwidgets={1}
showaddelement={true}
>
<BWidget
id="Header1"
type="Header"
title="My React Blog Header"
locked={true}
/>
</BSection>
<BIf cond="data:view.isHomepage">
<div className="homepage-banner">
<h1 expr:title="data:blog.title">
Welcome to {new BEval({ expr: "data:blog.title" })}!
</h1>
<p>A cutting-edge blog layout engineered entirely in TypeScript.</p>
</div>
</BIf>
</header>
);
const BlogLayout = () => (
<div className="wrapper-pane">
<BlogHeader />
<main className="content-area">
<BSection id="main-content-sec">
<BWidget id="Blog1" type="Blog">
<BIncludable id="main">
<BLoop values="data:posts" varName="post">
<div className="post-item-view" expr:id="data:post.id">
<h2 expr:class="data:post.class">
<a expr:href="data:post.url">
<BData value="post.title" />
</a>
</h2>
<div className="post-body">
<BData value="post.body" />
</div>
</div>
<BInclude name="postShareButtons" data="post" />
</BLoop>
</BIncludable>
</BWidget>
</BSection>
{/* Target element for React SPA mounting */}
<div id="react-root"></div>
{/* Embeds your React entry point with hot reloading support */}
<BClientScript scriptPath={REACT_APP_ENTRY} mode="cdata" />
</main>
</div>
);
function buildTheme() {
if (!fs.existsSync(DIST_DIR)) {
fs.mkdirSync(DIST_DIR, { recursive: true });
}
const theme = new BloggerTheme({
attributes: {
"b:responsive": "true",
"b:defaultwidgetversion": "2",
"b:layoutsversion": "3",
},
head: [
<Title id="ram">React Blogger Theme Example</Title>,
<BSkin css={OUTPUT_CSS_PATH} />,
],
body: [<BlogLayout />],
});
const xml = theme.generate();
const outputPath = path.resolve(DIST_DIR, "blogger-theme.xml");
fs.writeFileSync(outputPath, xml, "utf8");
console.log(`\n🎉 Success! Blogger XML theme generated at: ${outputPath}`);
}
buildTheme();
Step 5 Integrating an Embedded React App with BClientScript
One of the most powerful features of @antinna/blogger-theme is its ability to bundle a modern React application directly into Blogger's XML output. By utilizing the <BClientScript /> element, you can link to an external React component. The compiler automatically builds, compiles, and embeds this script into CDATA wrappers, allowing you to run a modern, interactive app directly inside Blogger:
import React, { useState } from "react";
export const App = () => {
const [count, setCount] = useState(0);
return (
<div className="p-6 bg-blue-50 rounded-xl border border-blue-200">
<h2 className="text-xl font-bold text-blue-900">Embedded React App 🚀</h2>
<p className="text-blue-700 mt-1">This component is bundled into Blogger CDATA.</p>
<button
onClick={() => setCount((c) => c + 1)}
className="mt-4 px-4 py-2 bg-blue-600 text-white font-medium rounded-lg shadow hover:bg-blue-700 transition-colors cursor-pointer"
>
Clicks: {count}
</button>
</div>
);
};
Step 6 Styling with Tailwind CSS and Building the Pipeline
To style your layout elements, write standard CSS inside a source file like style/src/input.css using standard Tailwind CSS classes. When you run the compilation command, the build pipeline processes your classes, compiles the Tailwind bundle into dist/output.css, and embeds it directly into the XML theme output via <BSkin css={OUTPUT_CSS_PATH} />!
Step 7 Quickstart Template Repository and Installation
To help you get started quickly, a pre-configured starter template is available. This template sets up the monorepo structure, Tailwind CSS build scripts, and React configurations automatically.
Avoid manual setup by cloning the official template repository:
👉 Tailwind React Blogger Template: github.com/mg3994/Blogger-Tailwind-React
To run and compile the template locally:
The compiler will watch your React components and stylesheet modifications, compiling them automatically into dist/blogger-theme.xml. Simply copy and paste this compiled XML file directly into Blogger's theme editor!
Step 8 Benefits of this Modern Approach
Moving your theme development to @antinna/blogger-theme brings several major benefits:
- Fully Component-Driven: Organize your theme using small, self-contained files (e.g.
Header.tsx,Sidebar.tsx,Footer.tsx) instead of a single massive file. - Robust Type-Safety: All properties, arrays, and Blogger constructs are fully typed, catching potential errors during development.
- Tailwind & React Integration: Use your favorite frontend libraries and styling tools directly inside Blogger, raising it to the standard of modern CMS systems.
Complete Conclusion & Next Steps
Developing templates for Blogger no longer requires writing rigid, unmanageable XML files. With @antinna/blogger-theme, you can build layouts using component-driven, type-safe React JSX files, styled with Tailwind CSS, and compiled automatically.
Clone the template repository, run npm install, and start customizing your layout using clean JSX components. Your compiled, responsive Blogger theme XML will be ready in seconds!
📄 Contributions & Feedback
We believe this modern development workflow makes building templates for Blogger both elegant and fun. What features are you planning to build with React and TypeScript inside your next Blogger theme? Let us know in the comments below!
