Getting Started
Welcome to HypertextTemplates.jl! This guide will help you get up and running with Julia's HTML templating system.
Installation
Add HypertextTemplates to your Julia project:
using Pkg
Pkg.add("HypertextTemplates")
Or in the Julia REPL's package mode (press ]
):
pkg> add HypertextTemplates
First Steps
Basic Usage
Every HTML element is a Julia macro. Use @render
to convert templates to HTML strings:
using HypertextTemplates
using HypertextTemplates.Elements
# Render a simple HTML fragment
html = @render @div begin
@h1 "Welcome to HypertextTemplates!"
@p "This is a simple example."
end
<div>
<h1>Welcome to HypertextTemplates!</h1>
<p>This is a simple example.</p>
</div>
Adding Attributes
Attributes use {}
syntax, similar to Julia NamedTuples:
using HypertextTemplates
using HypertextTemplates.Elements
html = @render @div {id = "main", class = "container"} begin
@h1 {class = "title"} "Styled Heading"
@p {style = "color: blue;"} "Blue text"
end
<div id="main" class="container">
<h1 class="title">Styled Heading</h1>
<p style="color: blue">Blue text</p>
</div>
Using Variables and Expressions
Use $
to interpolate variables and expressions. All values are automatically HTML-escaped for security:
using HypertextTemplates
using HypertextTemplates.Elements
name = "Julia"
count = 42
html = @render @div begin
@h1 "Hello, " $name "!"
@p "The answer is " $count
@p "Double the answer: " $(count * 2)
end
<div>
<h1>Hello, Julia!</h1>
<p>The answer is 42</p>
<p>Double the answer: 84</p>
</div>
Building a Simple Page
Let's create a complete HTML page structure:
using HypertextTemplates
using HypertextTemplates.Elements
# Build a complete page
html = @render @html begin
@head begin
@meta {charset = "UTF-8"}
@meta {name = "viewport", content = "width=device-width, initial-scale=1.0"}
@title "My First Page"
end
@body begin
@div {class = "container"} begin
@h1 "My First Page"
@section begin
@p "Welcome to my website built with HypertextTemplates.jl!"
@ul begin
@li "Fast rendering"
@li "Type-safe templates"
@li "Julia-native syntax"
end
end
end
end
end
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First Page</title>
</head>
<body>
<div class="container">
<h1>My First Page</h1>
<section>
<p>Welcome to my website built with HypertextTemplates.jl!</p>
<ul>
<li>Fast rendering</li>
<li>Type-safe templates</li>
<li>Julia-native syntax</li>
</ul>
</section>
</div>
</body>
</html>
Working with Loops
Julia's control flow integrates naturally:
using HypertextTemplates
using HypertextTemplates.Elements
items = ["Apple", "Banana", "Cherry"]
html = @render @ul begin
for item in items
@li $item
end
end
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
using HypertextTemplates
using HypertextTemplates.Elements
items = ["Apple", "Banana", "Cherry"]
# With enumeration
html = @render @ol begin
for (i, item) in enumerate(items)
@li {value = i * 10} "Item " $i ": " $item
end
end
<ol>
<li value="10">Item 1: Apple</li>
<li value="20">Item 2: Banana</li>
<li value="30">Item 3: Cherry</li>
</ol>
Conditional Rendering
Use standard Julia conditionals:
using HypertextTemplates
using HypertextTemplates.Elements
user_logged_in = true
username = "julia_dev"
html = @render @div begin
if user_logged_in
@p "Welcome back, " $username "!"
@button "Logout"
else
@p "Please log in to continue."
@button "Login"
end
end
<div>
<p>Welcome back, julia_dev!</p>
<button>Logout</button>
</div>
Creating Your First Component
Components are reusable template functions:
using HypertextTemplates
using HypertextTemplates.Elements
@component function card(; title, description, link_url = nothing, link_text = "Learn more")
@div {class = "card"} begin
@h3 {class = "card-title"} $title
@p {class = "card-description"} $description
if !isnothing(link_url)
@a {href = link_url, class = "card-link"} $link_text
end
end
end
# Important: Create a macro shortcut for easier use
@deftag macro card end
# Now you can use @card instead of @<card
html = @render @div {class = "card-grid"} begin
@card {
title = "Getting Started",
description = "Learn the basics of HypertextTemplates.jl"
}
@card {
title = "Advanced Features",
description = "Explore components, slots, and more",
link_url = "/docs/advanced",
link_text = "Explore"
}
end
<div class="card-grid">
<div class="card">
<h3 class="card-title">Getting Started</h3>
<p class="card-description">Learn the basics of HypertextTemplates.jl</p>
</div>
<div class="card">
<h3 class="card-title">Advanced Features</h3>
<p class="card-description">Explore components, slots, and more</p>
<a href="/docs/advanced" class="card-link">Explore</a>
</div>
</div>
Understanding Components
Components are functions that accept props and generate HTML. Use @deftag
to create a convenient macro shortcut:
Components with Slots
Slots allow components to accept child content:
using HypertextTemplates
using HypertextTemplates.Elements
@component function page(; title)
@html begin
@head begin
@meta {charset = "UTF-8"}
@meta {name = "viewport", content = "width=device-width, initial-scale=1.0"}
@title $title
end
@body begin
@div {class = "container"} begin
@h1 $title
@section begin
@__slot__
end
end
end
end
end
@deftag macro page end
# Use the page component with slot content
html = @render @page {title = "My First Page"} begin
@p "Welcome to my website built with HypertextTemplates.jl!"
@ul begin
@li "Fast rendering"
@li "Type-safe templates"
@li "Julia-native syntax"
end
end
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First Page</title>
</head>
<body>
<div class="container">
<h1>My First Page</h1>
<section>
<p>Welcome to my website built with HypertextTemplates.jl!</p>
<ul>
<li>Fast rendering</li>
<li>Type-safe templates</li>
<li>Julia-native syntax</li>
</ul>
</section>
</div>
</body>
</html>
The @__slot__
marker shows where child content renders inside the component.
Rendering to Different Outputs
By default, @render
returns a String, but you can specify other outputs:
# Render to an IO buffer
io = IOBuffer()
@render io @div "Hello, IO!"
result = String(take!(io))
# Render to a byte array
bytes = @render Vector{UInt8} @div "Hello, bytes!"
# Render to a file
open("output.html", "w") do file
@render file @html begin
@body @h1 "Saved to file!"
end
end
Next Steps
Now that you understand the basics:
- Learn about the Core Concepts underlying the DSL
- Explore the Component System for building reusable UI
- Understand HTML Elements & Attributes in detail
- Discover Advanced Features for complex applications
Common Pitfalls
Avoid these common mistakes when starting with HypertextTemplates:
1. Forgetting $
for Variables
# Wrong - variable not interpolated
name = "Julia"
@render @p "Hello, name" # Output: <p>Hello, name</p>
# Correct - use $ to interpolate
@render @p "Hello, " $name # Output: <p>Hello, Julia</p>
2. Missing begin...end
Blocks
# Wrong - syntax error
@render @div
@h1 "Title"
@p "Content"
# Correct - use begin...end for multiple elements
@render @div begin
@h1 "Title"
@p "Content"
end
3. Wrong Attribute Syntax
# Wrong - using parentheses
@render @div(class="container") "Content" # Syntax error!
# Correct - use curly braces
@render @div {class = "container"} "Content"
4. String Literals vs Expressions
# String literals are NOT escaped (trusted content)
@render @p "<b>Bold</b>" # Output: <p><b>Bold</b></p>
# Variables ARE escaped (safe from XSS)
text = "<b>Bold</b>"
@render @p $text # Output: <p><b>Bold</b></p>
5. Component Usage Without @deftag
# Define component
@component function my_button(; text = "Click")
@button {class = "btn"} $text
end
# Wrong - can't use as macro without @deftag
@render @my_button {text = "Submit"} # Error!
# Correct - either use @< or define a tag
@render @<my_button {text = "Submit"} # Works
# Or better, define the tag
@deftag macro my_button end
@render @my_button {text = "Submit"} # Now works!
Happy templating with HypertextTemplates.jl!