| Crates.io | docx-handlebars |
| lib.rs | docx-handlebars |
| version | 0.3.3 |
| created_at | 2025-06-26 13:17:12.785852+00 |
| updated_at | 2025-11-05 09:52:40.143054+00 |
| description | A Rust library for processing DOCX files with Handlebars templates, supporting WASM, Node.js, Deno, and browsers |
| homepage | https://github.com/sail-sail/docx-handlebars |
| repository | https://github.com/sail-sail/docx-handlebars |
| max_upload_size | |
| id | 1727316 |
| size | 89,584 |
A Rust library for processing DOCX files with Handlebars templates, supporting multiple platforms:
cargo add docx-handlebars
npm install docx-handlebars
import init, { render_template } from "jsr:@sail/docx-handlebars";
use docx_handlebars::render_template;
use serde_json::json;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read DOCX template file
let template_bytes = std::fs::read("template.docx")?;
// Prepare data
let data = json!({
"name": "John Doe",
"company": "ABC Technology Ltd.",
"position": "Software Engineer",
"projects": [
{"name": "Project A", "status": "Completed"},
{"name": "Project B", "status": "In Progress"}
],
"has_bonus": true,
"bonus_amount": 5000
});
// Render template
let result = render_template(template_bytes, &data)?;
// Save result
std::fs::write("output.docx", result)?;
Ok(())
}
import init, { render_template } from 'docx-handlebars';
import fs from 'fs';
async function processTemplate() {
// Initialize WASM module
await init();
// Read template file
const templateBytes = fs.readFileSync('template.docx');
// Prepare data
const data = {
name: "Jane Smith",
company: "XYZ Tech Ltd.",
position: "Senior Developer",
projects: [
{ name: "E-commerce Platform", status: "Completed" },
{ name: "Mobile App", status: "In Development" }
],
has_bonus: true,
bonus_amount: 8000
};
// Render template
const result = render_template(templateBytes, JSON.stringify(data));
// Save result
fs.writeFileSync('output.docx', new Uint8Array(result));
}
processTemplate().catch(console.error);
import init, { render_template } from "https://deno.land/x/docx_handlebars/mod.ts";
async function processTemplate() {
// Initialize WASM module
await init();
// Read template file
const templateBytes = await Deno.readFile("template.docx");
// Prepare data
const data = {
name: "Alice Johnson",
department: "R&D Department",
projects: [
{ name: "AI Customer Service", status: "Live" },
{ name: "Data Visualization Platform", status: "In Development" }
]
};
// Render template
const result = render_template(templateBytes, JSON.stringify(data));
// Save result
await Deno.writeFile("output.docx", new Uint8Array(result));
}
if (import.meta.main) {
await processTemplate();
}
<!DOCTYPE html>
<html>
<head>
<title>DOCX Handlebars Example</title>
</head>
<body>
<input type="file" id="fileInput" accept=".docx">
<button onclick="processFile()">Process Template</button>
<script type="module">
import init, { render_template } from './pkg/docx_handlebars.js';
// Initialize WASM
await init();
window.processFile = async function() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!file) return;
const arrayBuffer = await file.arrayBuffer();
const templateBytes = new Uint8Array(arrayBuffer);
const data = {
name: "John Doe",
company: "Example Company"
};
try {
const result = render_template(templateBytes, JSON.stringify(data));
// Download result
const blob = new Blob([new Uint8Array(result)], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'processed.docx';
a.click();
} catch (error) {
console.error('Processing failed:', error);
}
};
</script>
</body>
</html>
Employee Name: {{name}}
Company: {{company}}
Position: {{position}}
{{#if has_bonus}}
Bonus: ${{bonus_amount}}
{{else}}
No bonus
{{/if}}
{{#unless is_intern}}
Full-time employee
{{/unless}}
Project Experience:
{{#each projects}}
- {{name}}: {{description}} ({{status}})
{{/each}}
Skills:
{{#each skills}}
{{@index}}. {{this}}
{{/each}}
Built-in helper functions:
{{upper name}} <!-- Convert to uppercase -->
{{lower company}} <!-- Convert to lowercase -->
{{len projects}} <!-- Array length -->
{{#if (eq status "completed")}}Completed{{/if}} <!-- Equality comparison -->
{{#if (gt score 90)}}Excellent{{/if}} <!-- Greater than comparison -->
{{#if (lt age 30)}}Young{{/if}} <!-- Less than comparison -->
<!-- Image insertion -->
{{img base64_data}} <!-- Inline image -->
{{img base64_data 300 200}} <!-- Inline image with specified dimensions -->
{{img base64_data 300 200 options}} <!-- Floating image with positioning options -->
=== Employee Report ===
Basic Information:
Name: {{employee.name}}
Department: {{employee.department}}
Position: {{employee.position}}
Hire Date: {{employee.hire_date}}
{{#if employee.has_bonus}}
💰 Bonus: ${{employee.bonus_amount}}
{{/if}}
Project Experience ({{len projects}} total):
{{#each projects}}
{{@index}}. {{name}}
Description: {{description}}
Status: {{status}}
Team Size: {{team_size}} people
{{/each}}
Skills Assessment:
{{#each skills}}
- {{name}}: {{level}}/10 ({{years}} years experience)
{{/each}}
To delete an entire table row, simply add the following to any cell in that row:
{{removeTableRow}}
{{#if (gt performance.score 90)}}
🎉 Performance Rating: Excellent
{{else if (gt performance.score 80)}}
👍 Performance Rating: Good
{{else}}
📈 Performance Rating: Needs Improvement
{{/if}}
Image:
{{img base64_image_data [width] [height] [options]}}
only height: {{img base64 "" 200}}
only width: {{img base64 300}}
no width/height: {{img base64}}
both width/height: {{img base64 300 200}}
Floating image example:
{{img base64 200 100 options}}
Where options can be:
{
"anchor": true, // Whether to use anchor positioning (floating image)
"behind_doc": false, // Whether image is behind text (false=overlay text, true=text overlays image)
"allow_overlap": true, // Whether to allow overlap with other objects
"position_h": 40, // Horizontal offset in pixels (negative values shift left)
"position_v": -14 // Vertical offset in pixels (negative values shift up)
}
Image positioning guide:
- anchor: false (default) - Inline image, flows with text
- anchor: true - Floating image, can be freely positioned and overlay text
- position_h/position_v: When not provided, defaults to half the image size for centering
- Supports negative offsets for precise image positioning
# Build all targets
npm run build
# Or build separately
npm run build:web # Browser version
npm run build:npm # Node.js version
npm run build:jsr # Deno version
# Rust example
cargo run --example rust_example
# Node.js example
node examples/node_example.js
# Deno example
deno run --allow-read --allow-write examples/deno_example.ts
# Browser example
cd tests/npm_test
node serve.js
# Then open http://localhost:8080 in your browser
# Select examples/template.docx file to test
The core innovation of this library is the intelligent merging of Handlebars syntax that has been split by XML tags. In DOCX files, when users input template syntax, Word may split it into multiple XML tags.
This project is licensed under the MIT License - see the LICENSE-MIT file for details.
docx-handlebars - Making DOCX template processing simple and efficient
