Public API

The public API consists of all exported functions, macros, and types that are intended for end users. These APIs are stable and follow semantic versioning - breaking changes will only occur in major version updates. The public API includes the core @render macro, component definition utilities like @component and @deftag, security features like SafeString, and all the HTML element macros available through HypertextTemplates.Elements. These are the building blocks you'll use to create templates and components in your applications.

HypertextTemplates.HypertextTemplatesModule
HypertextTemplates

A hypertext templating DSL for Julia that allows writing HTML using native Julia syntax.

HypertextTemplates provides a macro-based DSL where all HTML elements are exposed as macros (e.g., @div, @p). It uses a special {} syntax for attributes that mimics NamedTuples, allowing natural integration of Julia control flow directly in templates.

Key Features

  • Zero-allocation rendering: Direct IO streaming without intermediate DOM
  • Component system: Reusable components with props and slots
  • Auto-escaping: Automatic HTML escaping for security (bypass with SafeString)
  • Streaming support: Efficient chunked rendering for large documents
  • Markdown integration: Render Markdown files as components (requires CommonMark.jl)

Basic Usage

using HypertextTemplates, HypertextTemplates.Elements

# Simple rendering
@render @div {class = "greeting"} "Hello, World!"

# Components with slots
@component function card(; title)
    @div {class = "card"} begin
        @h2 $title
        @div {class = "body"} @__slot__
    end
end

Main Exports

  • @render: Render templates to strings or IO
  • @component: Define reusable components
  • @deftag: Create macro shortcuts for components
  • SafeString: Mark content as pre-escaped HTML
  • StreamingRender: Iterator for chunked rendering
  • @<: Dynamic component/element rendering

See the documentation for detailed examples and advanced features.

source
HypertextTemplates.SafeStringType
SafeString(str::String)

A string wrapper that bypasses automatic HTML escaping.

By default, all string content is HTML-escaped to prevent XSS attacks. SafeString marks content as pre-escaped or trusted HTML that should be rendered as-is.

Security Risk

Only use SafeString with content you trust completely. Never wrap user input directly with SafeString without proper sanitization. This can lead to XSS vulnerabilities.

Arguments

  • str::String: The HTML string to mark as safe

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Normal strings are escaped
       @render @div "<b>Bold</b>"
"<div>&lt;b&gt;Bold&lt;/b&gt;</div>"

julia> # SafeString content is not escaped
       @render @div $(SafeString("<b>Bold</b>"))
"<div><b>Bold</b></div>"

julia> # Common use case: pre-rendered markdown
       markdown_html = "<p>Already <em>escaped</em> content</p>";

julia> @render @article $(SafeString(markdown_html))
"<article><p>Already <em>escaped</em> content</p></article>"

Security best practices

# GOOD: Content from trusted sources
html = markdown_to_html(user_content)  # Markdown processor escapes content
@render @div SafeString(html)

# GOOD: Your own HTML generation
safe_html = "<span class="highlight">Important</span>"
@render @div SafeString(safe_html)

# BAD: Never do this with user input!
user_input = get_user_input()
@render @div SafeString(user_input)  # DANGER: XSS vulnerability!

See also: @render, escape_html, @esc_str

source
HypertextTemplates.StreamingRenderType
StreamingRender(func; kwargs...)
StreamingRender(; kwargs...) do io
    # render content
end

Create an iterator for streaming template rendering.

StreamingRender enables efficient rendering of large templates by yielding chunks of output as they become available. This is particularly useful for:

  • HTTP streaming responses
  • Large documents that would consume too much memory if rendered at once
  • Progressive rendering where content appears as it's generated

The function uses intelligent micro-batching: large writes (≥64 bytes) are sent immediately for low latency, while smaller writes are batched for efficiency.

Arguments

  • func: Function that takes an io argument to pass to @render

Keywords

  • buffer_size::Int=32: Number of chunks the channel can buffer before blocking
  • chunk_size::Int=4096: Legacy parameter (kept for compatibility, no longer used)
  • immediate_threshold::Int=64: Bytes above which writes bypass buffering for low latency

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Collect all chunks (for demonstration)
       chunks = String[];

julia> for chunk in StreamingRender() do io
           @render io @div begin
               @h1 "Header"
               @p "Content"
           end
       end
           push!(chunks, String(chunk))
       end

julia> join(chunks)
"<div><h1>Header</h1><p>Content</p></div>"

HTTP streaming example

using HTTP
using HypertextTemplates, HypertextTemplates.Elements

function handle_request(req)
    HTTP.Response(200, ["Content-Type" => "text/html"]) do io
        for chunk in StreamingRender() do render_io
            @render render_io @html begin
                @head @title "Streaming Page"
                @body begin
                    @h1 "Live Data"
                    for i in 1:1000
                        @div "Item $i"
                    end
                end
            end
        end
            write(io, chunk)
        end
    end
end

Progressive rendering

# Stream data as it becomes available
for chunk in StreamingRender() do io
    @render io @div begin
        @h1 "Results"
        for result in fetch_results_lazily()
            @article begin
                @h2 result.title
                @p result.content
            end
        end
    end
end
    # Send chunk to client immediately
    write(client_connection, chunk)
    flush(client_connection)
end

See also: @render, MicroBatchWriter

source
HypertextTemplates.@<Macro
@<component_or_element
@<component_or_element children...
@<component_or_element {props...}
@<component_or_element {props...} children...

Dynamically render a component or element from a variable.

The @< macro enables dynamic component selection, where the component or element to render is determined at runtime. This is useful for polymorphic rendering, component mappings, and conditional component selection.

Arguments

  • component_or_element: A variable containing a component function or element
  • props...: Optional properties in {} syntax
  • children...: Optional child content

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Dynamic element selection
       tag = Elements.div
       @render @<tag {class = "dynamic"} "Content"
"<div class=\"dynamic\">Content</div>"

julia> # Change element at runtime
       tag = span
       @render @<tag {class = "dynamic"} "Content"
"<span class=\"dynamic\">Content</span>"

Dynamic component selection

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Define components
       @component function info_box(; message)
           @div {class = "info"} @p $message
       end;

julia> @component function error_box(; message)
           @div {class = "error"} @strong $message
       end;

julia> # Select component based on condition
       function render_message(type, message)
           component = type == :error ? error_box : info_box
           @render @<component {message}
       end
render_message (generic function with 1 method)

julia> render_message(:info, "All good!")
"<div class=\"info\"><p>All good!</p></div>"

julia> render_message(:error, "Something went wrong!")
"<div class=\"error\"><strong>Something went wrong!</strong></div>"

With slots

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function wrapper(; variant = "default")
           @div {class = "wrapper-$variant"} @__slot__
       end;

julia> # Dynamic wrapper
       w = wrapper
       @render @<w {variant = "special"} begin
           @h1 "Wrapped content"
       end
"<div class=\"wrapper-special\"><h1>Wrapped content</h1></div>"

See also: @component, @deftag

source
HypertextTemplates.@__once__Macro
@__once__ begin
    # content to render once
end

Render content only once per @render call.

The @__once__ macro ensures that its content is rendered only once, even if the containing component is used multiple times within the same render tree. This is essential for including CSS, JavaScript, or other resources that should not be duplicated.

Common use cases

  • CSS styles that should appear once
  • JavaScript libraries and initialization code
  • Meta tags or link elements in components
  • Any content that would cause issues if duplicated

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function button_with_styles(; text, variant = "primary")
           @__once__ begin
               @style """
               .btn { padding: 10px; border: none; cursor: pointer; }
               .btn-primary { background: blue; color: white; }
               .btn-danger { background: red; color: white; }
               """
           end
           @button {class = "btn btn-$variant"} $text
       end;

julia> @deftag macro button_with_styles end
@button_with_styles (macro with 1 method)

JavaScript dependencies

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function chart(; data)
           @__once__ begin
               @script {src = "https://cdn.plot.ly/plotly-latest.min.js"}
           end
           @div {id = "chart-$(hash(data))"} begin
               @script """
               Plotly.newPlot('chart-$(hash(data))', $(data));
               """
           end
       end;

julia> @deftag macro chart end
@chart (macro with 1 method)

Scope behavior

Each @render call maintains its own set of rendered once-blocks:

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function with_header()
           @__once__ @h1 "Page Header"
           @p "Content"
       end;

julia> @deftag macro with_header end
@with_header (macro with 1 method)

julia> # First render includes the header
       @render @with_header
"<h1>Page Header</h1><p>Content</p>"

julia> # Second render also includes it (different @render call)
       @render @with_header
"<h1>Page Header</h1><p>Content</p>"

See also: @component, @render

source
HypertextTemplates.@__slot__Macro
@__slot__ [name]

Define a content slot within a component.

Slots enable content projection - allowing parent components to pass content into specific locations within child components. This is essential for creating flexible, composable components.

Arguments

  • name: Optional slot name. If omitted, creates the default slot.

Default slot

The default slot (no name) receives all content passed to the component that isn't assigned to a named slot.

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function card(; title)
           @div {class = "card"} begin
               @h2 $title
               @div {class = "content"} @__slot__
           end
       end;

julia> @deftag macro card end
@card (macro with 1 method)

julia> @render @card {title = "Welcome"} begin
           @p "This goes into the default slot"
           @p "So does this"
       end
"<div class=\"card\"><h2>Welcome</h2><div class=\"content\"><p>This goes into the default slot</p><p>So does this</p></div></div>"

Named slots

Named slots receive only content explicitly assigned to them using name := content syntax.

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function modal(; title = "")
           @div {class = "modal"} begin
               @header begin
                   @h2 $title
                   @__slot__ header_actions
               end
               @div {class = "body"} @__slot__
               @footer @__slot__ footer
           end
       end;

julia> @deftag macro modal end
@modal (macro with 1 method)

julia> @render @modal {title = "Confirm"} begin
           # Default slot content
           @p "Are you sure?"
           # Named slot content
           header_actions := @button {class = "close"} "×"
           footer := begin
               @button "Cancel"
               @button {class = "primary"} "OK"
           end
       end
"<div class=\"modal\"><header><h2>Confirm</h2><button class=\"close\">×</button></header><div class=\"body\"><p>Are you sure?</p></div><footer><button>Cancel</button><button class=\"primary\">OK</button></footer></div>"

See also: @component

source
HypertextTemplates.@cm_componentMacro
@cm_component component_name(; props...) = "file_name.md"

Create a component from a Markdown file.

This macro creates a component that renders Markdown content from a file. The Markdown is parsed using CommonMark.jl and can include interpolated values using $variable syntax.

Note

This feature requires CommonMark.jl to be installed as it's provided via Julia's package extension mechanism.

Arguments

  • component_name: Name for the component function
  • props...: Optional keyword arguments that can be interpolated in the Markdown
  • file_name.md: Path to the Markdown file (relative to the current file)

Features

  • Interpolation: Use $prop_name in Markdown to insert prop values
  • Live reload: With Revise.jl, changes to the Markdown file auto-update
  • Compile-time parsing: Without Revise.jl, Markdown is parsed at compile time for performance

Examples

Basic usage

# In article.md:
# # $title
# 
# By $author on $date
# 
# $content

# In your Julia code:
using HypertextTemplates, HypertextTemplates.Elements
using CommonMark

@cm_component article(; title, author, date, content) = "article.md"
@deftag macro article end

@render @article {
    title = "Hello World",
    author = "Jane Doe",
    date = "2024-01-15",
    content = "This is my first post!"
}

Directory structure

# components/header.md contains:
# # $site_name
# 
# *$tagline*

# In components/components.jl:
@cm_component header(; site_name, tagline = "Welcome") = "header.md"

# Path is relative to the file containing @cm_component

With default values

@cm_component footer(; copyright_year = 2024, company = "Acme Corp") = "footer.md"
@deftag macro footer end

# Uses defaults
@render @footer

# Override defaults
@render @footer {copyright_year = 2025}

Complex content interpolation

# In template.md:
# # Product: $name
# 
# Price: $$$price
# 
# $description

@cm_component product_card(; name, price, description) = "template.md"
@deftag macro product_card end

@render @product_card {
    name = "Widget",
    price = 19.99,
    description = "A **fantastic** widget with _many_ features!"
}
Development workflow

When using Revise.jl, you can edit the Markdown file and see changes immediately without restarting Julia or redefining the component.

See also: @component, SafeString

source
HypertextTemplates.@componentMacro
@component function component_name(; properties...)
    # template body
end

Define a reusable component function.

Components are functions that return template content and can accept properties as keyword arguments. They enable code reuse and composition in templates.

After defining a component, use @deftag to create a convenient macro for using it like a regular HTML element.

Arguments

  • component_name: The name of the component function
  • properties...: Keyword arguments that become the component's props

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function greeting(; name = "World")
           @h1 "Hello, " $name "!"
       end
greeting (generic function with 1 method)

julia> @deftag macro greeting end
@greeting (macro with 1 method)

julia> @render @greeting {name = "Julia"}
"<h1>Hello, Julia!</h1>"

julia> @render @greeting  # Uses default value
"<h1>Hello, World!</h1>"

Components with slots

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function card(; title)
           @div {class = "card"} begin
               @h2 $title
               @div {class = "body"} @__slot__
           end
       end
card (generic function with 1 method)

julia> @deftag macro card end
@card (macro with 1 method)

julia> @render @card {title = "Info"} begin
           @p "Card content goes here"
       end
"<div class=\"card\"><h2>Info</h2><div class=\"body\"><p>Card content goes here</p></div></div>"

Typed props for safety

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function price(; amount::Number, currency::String = "USD")
           @span {class = "price"} $currency " " $(round(amount, digits=2))
       end
price (generic function with 1 method)

julia> @deftag macro price end
@price (macro with 1 method)

julia> @render @price {amount = 19.999}
"<span class=\"price\">USD 20.0</span>"

See also: @deftag, @__slot__, @render

source
HypertextTemplates.@contextMacro
@context {key = value, ...} body
@context {key, ...} body

Set context values that will be available to all child components.

The @context macro allows passing data through the component tree without explicit prop drilling. It uses Julia's IOContext mechanism to store key-value pairs that can be retrieved by child components using @get_context.

Supports both explicit key = value syntax and shorthand key syntax (which expands to key = key).

Arguments

  • Key-value pairs or shorthand symbols in {} syntax specifying the context data
  • body: The content that will have access to the context

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function themed_button(; text = "Click me")
           theme = @get_context(:theme, "light")
           @button {class = "btn-$theme"} $text
       end;

julia> @deftag macro themed_button end
@themed_button (macro with 1 method)

julia> @render @context {theme = "dark"} begin
           @themed_button {text = "Dark Button"}
       end
"<button class=\"btn-dark\">Dark Button</button>"

julia> # Shorthand syntax
       theme = "blue"
       @render @context {theme} begin  # Same as {theme = theme}
           @themed_button
       end
"<button class=\"btn-blue\">Click me</button>"

julia> # Mixed syntax
       user = "alice"
       @render @context {user, theme = "dark"} begin
           @div begin
               @text "User: " @get_context(:user)
               @themed_button
           end
       end
"<div>User: alice<button class=\"btn-dark\">Click me</button></div>"

See also: @get_context, @component

source
HypertextTemplates.@deftagMacro
@deftag macro name end
@deftag name

Create a macro shortcut for using a component or element.

After defining a component with @component, use @deftag to create a convenient macro that allows using the component like an HTML element.

The macro name end syntax is preferred as it allows the LSP to correctly track the macro definition location.

Arguments

  • name: Symbol name of the component/element to create a macro for

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Define a component
       @component function alert(; type = "info", dismissible = false)
           @div {class = "alert alert-$type"} begin
               @__slot__
               if dismissible
                   @button {class = "close"} "×"
               end
           end
       end
alert (generic function with 1 method)

julia> # Create macro (preferred syntax for LSP support)
       @deftag macro alert end
@alert (macro with 1 method)

julia> # Now use like an HTML element
       @render @alert {type = "warning"} "Watch out!"
"<div class=\"alert alert-warning\">Watch out!</div>"

julia> # Alternative syntax (works but no LSP support)
       @component function message(; text)
           @p {class = "message"} $text
       end
message (generic function with 1 method)

julia> @deftag message
@message (macro with 1 method)

julia> @render @message {text = "Hello"}
"<p class=\"message\">Hello</p>"

Custom elements

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # Define a custom HTML element
       @element "my-widget" my_widget

julia> @deftag macro my_widget end
@my_widget (macro with 1 method)

julia> @render @my_widget {id = "w1"} "Custom element"
"<my-widget id=\"w1\">Custom element</my-widget>"

See also: @component, @element, @<

source
HypertextTemplates.@elementMacro
@element html_tag_name [julia_name]

Define a custom HTML element.

Creates a new HTML element that can be used with HypertextTemplates' macro syntax. This is useful for custom elements, web components, or HTML elements not included in the default set.

Arguments

  • html_tag_name: The HTML tag name as it will appear in output (e.g., "my-element")
  • julia_name: Optional Julia identifier name (defaults to html_tag_name with invalid characters replaced)

Examples

julia> using HypertextTemplates

julia> # Define a custom element
       @element "my-widget" my_widget

julia> # Use with @deftag for macro syntax
       @deftag macro my_widget end
@my_widget (macro with 1 method)

julia> @render @my_widget {id = "w1", class = "custom"} "Widget content"
"<my-widget id=\"w1\" class=\"custom\">Widget content</my-widget>"

Web Components

julia> using HypertextTemplates

julia> # Define web component elements
       @element "ion-button" ion_button

julia> @element "ion-icon" ion_icon

julia> @deftag macro ion_button end
@ion_button (macro with 1 method)

julia> @deftag macro ion_icon end
@ion_icon (macro with 1 method)

julia> @render @ion_button {color = "primary", expand = "block"} begin
           @ion_icon {name = "save-outline", slot = "start"}
           "Save"
       end
"<ion-button color=\"primary\" expand=\"block\"><ion-icon name=\"save-outline\" slot=\"start\"></ion-icon>Save</ion-button>"

See also: @deftag, @component

source
HypertextTemplates.@esc_strMacro
@esc_str

Escape HTML at compile time and return a SafeString.

This string macro performs HTML escaping during macro expansion rather than at runtime, providing better performance for static content that needs escaping.

The resulting SafeString will not be escaped again during rendering.

See also: SafeString, escape_html

source
HypertextTemplates.@get_contextMacro
@get_context(key)
@get_context(key, default)

Retrieve a value from the current context.

The @get_context macro retrieves values that were set by parent @context blocks. It accesses the IOContext chain to find the requested key.

Arguments

  • key: The context key to retrieve (as a symbol or string)
  • default: Optional default value if the key is not found

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @component function user_greeting()
           user = @get_context(:user, "Guest")
           @p "Hello, $(user)!"
       end;

julia> @deftag macro user_greeting end
@user_greeting (macro with 1 method)

julia> @render @context {user = "Alice"} begin
           @user_greeting
       end
"<p>Hello, Alice!</p>"

julia> # Without context, uses default
       @render @user_greeting
"<p>Hello, Guest!</p>"

julia> # Access multiple context values
       @component function profile_card()
           user = @get_context(:user, "Unknown")
           theme = @get_context(:theme, "light")
           role = @get_context(:role)  # No default
           @div {class = "profile-$theme"} begin
               @h3 $user
               !isnothing(role) && @span {class = "role"} $role
           end
       end;

See also: @context, @component

source
HypertextTemplates.@renderMacro
@render [destination] dom

Render a template to the given destination.

If no destination is provided, renders to a String and returns it. The destination can be any IO object (e.g., stdout, IOBuffer, file handle) or a type like String or Vector{UInt8}.

This macro is only needed for rendering the root of the DOM tree, not for the output of each individual component that is defined.

Arguments

  • destination: Optional IO object or type to render to (default: String)
  • dom: The template expression to render

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> @render @div "Hello, World!"
"<div>Hello, World!</div>"

julia> buffer = IOBuffer();

julia> @render buffer @span {class = "greeting"} "Hi!";

julia> String(take!(buffer))
"<span class=\"greeting\">Hi!</span>"

julia> @render Vector{UInt8} @p "Binary output"
20-element Vector{UInt8}:
 0x3c
 0x70
 0x3e
 0x42
 0x69
 0x6e
 0x61
 0x72
 0x79
 0x20
 0x6f
 0x75
 0x74
 0x70
 0x75
 0x74
 0x3c
 0x2f
 0x70
 0x3e

Rendering to files

open("output.html", "w") do file
    @render file @html begin
        @head @title "My Page"
        @body @h1 "Hello!"
    end
end

See also: StreamingRender, @component

source
HypertextTemplates.@textMacro
@text content...

Explicitly render content as text within templates.

The @text macro explicitly marks content for text rendering with HTML escaping. It is rarely needed directly since the $ interpolation syntax provides the same functionality more concisely.

Text content is automatically HTML-escaped unless wrapped in SafeString.

Arguments

  • content...: One or more values to render as text

Examples

julia> using HypertextTemplates, HypertextTemplates.Elements

julia> # HTML is escaped by default
       @render @div @text "<script>alert('XSS')</script>"
"<div>&lt;script&gt;alert('XSS')&lt;/script&gt;</div>"

julia> # Mix with elements
       @render @div begin
           @h1 "Title"
           @text "Some text content"
           @p "In a paragraph"
       end
"<div><h1>Title</h1>Some text content<p>In a paragraph</p></div>"
Tip

The $ interpolation syntax is preferred over @text in most cases:

# Preferred
@div "Count: " $count

# Equivalent but verbose
@div "Count: " @text count

See also: SafeString, escape_html

source
HypertextTemplates.ElementsModule
HypertextTemplates.Elements

Standard HTML elements for use with HypertextTemplates.

This module provides all standard HTML5 elements as both functions and macros. Each element can be used either as a macro (e.g., @div) or accessed as a function (e.g., Elements.div).

Usage

using HypertextTemplates, HypertextTemplates.Elements

# Use elements as macros
@render @div {class = "container"} begin
    @h1 "Title"
    @p "Content"
end

# Or access them as values for dynamic rendering
element = rand() > 0.5 ? Elements.div : Elements.span
@render @<element "Dynamic content"

Available Elements

All standard HTML5 elements are available, including:

  • Document structure: html, head, body, div, span
  • Text content: p, h1-h6, blockquote, pre
  • Forms: form, input, textarea, select, button
  • Media: img, video, audio, canvas
  • Tables: table, tr, td, th
  • And many more...

Special Behavior

  • The @html element automatically includes <!DOCTYPE html>
  • Void elements (like br, img, input) are self-closing
source