A lightweight TypeScript & ESNext library for generating Blogger (Blogspot) theme XML using a clean, declarative component API with full TSX/JSX and Builder support.
Inspired by the Dart library blogger_theme, this package enables writing highly modular, extensible Blogger themes with TypeScript.
- Declarative theme authoring in TypeScript using custom TSX/JSX elements or native Builder classes.
- Dual API Support (Option C): Use standard OOP constructors (
new BSection(...)), functional builders, or standard TSX layouts. - XML-Safe rendering: Automatic XML entity escaping and removal of XML 1.0 control characters.
- TypeScript 5+ and ESNext-native: Fully typed, clean, modern ES module structure.
- On-Demand client script compilation: Compile, bundle, and minify client-side TypeScript/JavaScript to self-invoking IIFEs inside Blogger templates using
esbuildat render-time. - Direct rendering: Directly render any component using
.render().
npm install @antinna/blogger-themeMake sure you have esbuild installed for the client script bundling feature.
To use TSX/JSX syntax in your project, configure your tsconfig.json with the automatic JSX runtime:
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"jsx": "react-jsx",
"jsxImportSource": "@antinna/blogger-theme",
"strict": true
}
}You can compile a theme entry file from the command line:
npx @antinna/blogger-theme ./example/main.tsx --out ./theme.xmlUseful flags:
-o, --out <file>: write the generated XML to a file-w, --watch: watch the entry file and its imports for changes-h, --help: show help
import { BSection, BWidget, BIf, BData } from "@antinna/blogger-theme";
export const BlogLayout = () => (
<div class="wrapper-pane">
<BSection
id="header-area"
className="header-section"
maxwidgets={1}
showaddelement={true}
>
<BWidget
id="Header1"
type="Header"
title="Blog Header Title"
locked={true}
/>
</BSection>
<BIf cond="data:view.isPost">
<div class="post-item">
<BData value="post.body" />
</div>
</BIf>
</div>
);import { BloggerTheme, Title, BSkin } from "@antinna/blogger-theme";
import { BlogLayout } from "./BlogLayout.js";
const theme = new BloggerTheme({
attributes: {
"b:responsive": "true",
"b:defaultwidgetversion": "2",
"b:layoutsversion": "3",
},
head: [
<Title>My Modern Blogger Theme</Title>,
<BSkin css="body { font-family: sans-serif; background: #fafafa; }" />,
],
body: [<BlogLayout />],
});
const xml = theme.generate();
console.log(xml);This library has been meticulously designed to support both styles natively.
If you prefer class-based instantiation matching the original Dart package:
import { BSection, BWidget, BIf, Div, BData } from "@antinna/blogger-theme";
const layout = new Div(
{ class: "wrapper-pane" },
new BSection(
{
id: "header-area",
className: "header-section",
maxwidgets: 1,
showaddelement: true,
},
new BWidget({
id: "Header1",
type: "Header",
title: "Blog Header Title",
locked: true,
}),
),
new BIf(
{ cond: "data:view.isPost" },
new Div({ class: "post-item" }, new BData("post.body")),
),
);
const xml = layout.render();You can compile a client-side TypeScript or JavaScript file at render-time. This code will be bundled, minified, wrapped inside a self-invoking IIFE, and output directly inside the rendered theme XML's <script> tag.
import { BClientScript } from "@antinna/blogger-theme";
// Inside your layout/head:
<BClientScript scriptPath="./src/client/analytics.ts" contentInCDATA={true} />;Component: Abstract base class for all nodes. Includes direct.render()method.DomComponent: Standard element with custom tag, attributes, and children.Text: Normal text node (XML escaped by default).RawText: Raw text node (disables XML escaping).Fragment: Group components without adding a parent tag.Renderer: Compiles component trees into XML strings.
BSection,BWidget,BWidgetSettings,BWidgetSettingBIf,BElseIf,BElseBLoop,BData,BArg,BAttr,BClassBInclude,BIncludable,BTag,BEvalBSkin,BVariable,BGroupBComment,XmlComment,BTemplateSkin,BTemplateScript,BParamBDefaultMarkup,BDefaultMarkups
Html,Head,Body,Title,Meta,Link,BaseDiv,Span,P,Form,Input,Button,Img,Br,HrHeader,Footer,Main,Nav,Section,Article,AsideH1,H2,H3,H4,H5,H6Ul,Li,A,Label,Select,Option,Script
MIT License.