12 KiB
Pugz Complete Features Reference
This document provides a comprehensive overview of ALL Pug features supported by Pugz, with examples from the demo templates.
✅ Fully Supported Features
1. Doctypes
Declare the HTML document type at the beginning of your template.
Examples:
doctype html
doctype xml
doctype transitional
doctype strict
doctype frameset
doctype 1.1
doctype basic
doctype mobile
Demo Location: pages/all-features.pug (Section 1)
Rendered HTML:
<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2. Tags
Basic HTML tags with automatic nesting based on indentation.
Examples:
// Basic tags
p This is a paragraph
div This is a div
span This is a span
// Nested tags
ul
li Item 1
li Item 2
li Item 3
// Self-closing tags
img(src="/image.png")
br
hr
meta(charset="utf-8")
// Block expansion (inline nesting)
a: img(src="/icon.png")
Demo Location: pages/all-features.pug (Section 2)
3. Attributes
Basic Attributes:
a(href="/link" target="_blank" rel="noopener") Link
input(type="text" name="username" placeholder="Enter name")
Boolean Attributes:
input(type="checkbox" checked)
button(disabled) Disabled
option(selected) Selected
Class & ID Shorthand:
div#main-content Main content
.card Card element
#sidebar.widget.active Multiple classes with ID
Multiple Classes (Array):
div(class=['btn', 'btn-primary', 'btn-large']) Button
Style Attributes:
div(style="color: blue; font-weight: bold;") Styled text
div(style={color: 'red', background: 'yellow'}) Object style
Data Attributes:
div(data-id="123" data-name="example" data-active="true") Data attrs
Attribute Interpolation:
- var url = '/page'
a(href='/' + url) Link
a(href=url) Direct variable
button(class=`btn btn-${type}`) Template string
Demo Location: pages/attributes-demo.pug, pages/all-features.pug (Section 3)
4. Plain Text
Inline Text:
p This is inline text after the tag.
Piped Text:
p
| This is piped text.
| Multiple lines.
| Each line starts with a pipe.
Block Text (Dot Notation):
script.
if (typeof console !== 'undefined') {
console.log('JavaScript block');
}
style.
.class { color: red; }
Literal HTML:
<div class="literal">
<p>This is literal HTML</p>
</div>
Demo Location: pages/all-features.pug (Section 4)
5. Text Interpolation
Escaped Interpolation (Default - Safe):
p Hello, #{name}!
p Welcome to #{siteName}.
Unescaped Interpolation (Use with caution):
p Raw HTML: !{htmlContent}
Tag Interpolation:
p This has #[strong bold text] and #[a(href="/") links] inline.
p You can #[em emphasize] words in the middle of sentences.
Demo Location: pages/all-features.pug (Section 5)
6. Code (Buffered Output)
Escaped Buffered Code (Safe):
p= username
div= content
span= email
Unescaped Buffered Code (Unsafe):
div!= htmlContent
p!= rawMarkup
Demo Location: pages/all-features.pug (Section 6)
7. Comments
HTML Comments (Visible in Source):
// This appears in rendered HTML as <!-- comment -->
p Content after comment
Silent Comments (Not in Output):
//- This is NOT in the HTML output
p Content
Block Comments:
//-
This entire block is commented out.
Multiple lines.
None of this appears in output.
Demo Location: pages/all-features.pug (Section 7)
8. Conditionals
If Statement:
if isLoggedIn
p Welcome back!
If-Else:
if isPremium
p Premium user
else
p Free user
If-Else If-Else:
if role === "admin"
p Admin access
else if role === "moderator"
p Moderator access
else
p Standard access
Unless (Negative Conditional):
unless isLoggedIn
a(href="/login") Please log in
Demo Location: pages/conditional.pug, pages/all-features.pug (Section 8)
9. Case/When (Switch Statements)
Basic Case:
case status
when "active"
.badge Active
when "pending"
.badge Pending
when "suspended"
.badge Suspended
default
.badge Unknown
Multiple Values:
case userType
when "admin"
when "superadmin"
p Administrative access
when "user"
p Standard access
default
p Guest access
Demo Location: pages/all-features.pug (Section 9)
10. Iteration (Each Loops)
Basic Each:
ul
each item in items
li= item
Each with Index:
ol
each value, index in numbers
li Item #{index}: #{value}
Each with Else (Fallback):
ul
each product in products
li= product
else
li No products available
Demo Location: pages/features-demo.pug, pages/all-features.pug (Section 10)
11. Mixins (Reusable Components)
Basic Mixin:
mixin button(text, type='primary')
button(class=`btn btn-${type}`)= text
+button('Click Me')
+button('Submit', 'success')
Mixin with Default Parameters:
mixin card(title='Untitled', content='No content')
.card
.card-header= title
.card-body= content
+card()
+card('My Title', 'My content')
Mixin with Blocks:
mixin article(title)
.article
h1= title
if block
block
else
p No content provided
+article('Hello')
p This is the article content.
p Multiple paragraphs.
Mixin with Attributes:
mixin link(href, name)
a(href=href)&attributes(attributes)= name
+link('/page', 'Link')(class="btn" target="_blank")
Rest Arguments:
mixin list(id, ...items)
ul(id=id)
each item in items
li= item
+list('my-list', 1, 2, 3, 4)
Demo Location: mixins/*.pug, pages/all-features.pug (Section 11)
12. Includes (Partials)
Include external Pug files as partials:
include partials/header.pug
include partials/footer.pug
div.content
p Main content
Demo Location: All pages use include for mixins and partials
13. Template Inheritance (Extends/Blocks)
Layout File (layouts/main.pug):
doctype html
html
head
block head
title Default Title
body
include ../partials/header.pug
block content
p Default content
include ../partials/footer.pug
Page File (pages/home.pug):
extends ../layouts/main.pug
block head
title Home Page
block content
h1 Welcome Home
p This is the home page content.
Block Append/Prepend:
extends layout.pug
block append scripts
script(src="/extra.js")
block prepend styles
link(rel="stylesheet" href="/custom.css")
Demo Location: All pages in pages/ extend layouts from layouts/
❌ Not Supported Features
1. Filters
Filters like :markdown, :coffee, :cdata are not supported.
Not Supported:
:markdown
# Heading
This is **markdown**
Workaround: Pre-process markdown to HTML before passing to template.
2. JavaScript Expressions
Unbuffered code and JavaScript expressions are not supported.
Not Supported:
- var x = 1
- var items = [1, 2, 3]
- if (x > 0) console.log('test')
Workaround: Pass data from Zig code instead of defining in template.
3. Nested Field Access
Only top-level field access is supported in data binding.
Not Supported:
p= user.name
p #{address.city}
Supported:
p= userName
p #{city}
Workaround: Flatten data structures before passing to template.
📊 Feature Support Matrix
| Feature | Runtime Mode | Compiled Mode | Notes |
|---|---|---|---|
| Doctypes | ✅ | ✅ | All standard doctypes |
| Tags | ✅ | ✅ | Including self-closing |
| Attributes | ✅ | ✅ | Static and dynamic |
| Plain Text | ✅ | ✅ | Inline, piped, block, literal |
| Interpolation | ✅ | ✅ | Escaped and unescaped |
| Buffered Code | ✅ | ✅ | = and != |
| Comments | ✅ | ✅ | HTML and silent |
| Conditionals | ✅ | 🚧 | Partial compiled support |
| Case/When | ✅ | 🚧 | Partial compiled support |
| Iteration | ✅ | ❌ | Runtime only |
| Mixins | ✅ | ❌ | Runtime only |
| Includes | ✅ | ❌ | Runtime only |
| Extends/Blocks | ✅ | ❌ | Runtime only |
| Filters | ❌ | ❌ | Not supported |
| JS Expressions | ❌ | ❌ | Not supported |
| Nested Fields | ❌ | ❌ | Not supported |
Legend:
- ✅ Fully Supported
- 🚧 Partial Support / In Progress
- ❌ Not Supported
🎯 Usage Examples
Runtime Mode (Full Feature Support)
const std = @import("std");
const pugz = @import("pugz");
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const html = try pugz.renderTemplate(arena.allocator(),
\\extends layouts/main.pug
\\
\\block content
\\ h1 #{title}
\\ each item in items
\\ p= item
, .{
.title = "My Page",
.items = &[_][]const u8{"One", "Two", "Three"},
});
std.debug.print("{s}\n", .{html});
}
Compiled Mode (Best Performance)
const std = @import("std");
const templates = @import("generated/root.zig");
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
// Simple page without extends/loops/mixins
const html = try templates.home.render(arena.allocator(), .{
.title = "Home Page",
.name = "Alice",
});
std.debug.print("{s}\n", .{html});
}
📂 Demo Files by Feature
| Feature | Demo File | Description |
|---|---|---|
| All Features | pages/all-features.pug |
Comprehensive demo of every feature |
| Attributes | pages/attributes-demo.pug |
All attribute syntax variations |
| Features | pages/features-demo.pug |
Mixins, loops, case, conditionals |
| Conditionals | pages/conditional.pug |
Simple if/else example |
| Layouts | layouts/main.pug |
Full layout with extends/blocks |
| Mixins | mixins/*.pug |
Buttons, forms, cards, alerts |
| Partials | partials/*.pug |
Header, footer components |
🚀 Quick Start
-
Compile the CLI tool:
cd /path/to/pugz zig build -
Compile simple templates (no extends/includes):
./zig-out/bin/cli --dir src/tests/examples/cli-templates-demo --out generated pages -
Use runtime mode for full feature support:
const engine = pugz.ViewEngine.init(.{ .views_dir = "src/tests/examples/cli-templates-demo", }); const html = try engine.render(allocator, "pages/all-features", data);
💡 Best Practices
-
Use Runtime Mode for:
- Templates with extends/includes
- Dynamic mixins
- Complex iteration patterns
- Development and rapid iteration
-
Use Compiled Mode for:
- Simple static pages
- High-performance production deployments
- Maximum type safety
- Embedded templates
-
Security:
- Always use
#{}(escaped) for user input - Only use
!{}(unescaped) for trusted content - Validate and sanitize data before passing to templates
- Always use
📚 Reference Links
- Pug Official Language Reference: https://pugjs.org/language/
- Pugz GitHub Repository: (your repo URL)
- Zig Programming Language: https://ziglang.org/
Version: Pugz 1.0
Zig Version: 0.15.2
Pug Syntax Version: Pug 3