Templates
This page shows how to use templates with Vix Core.
Use it when you want to render HTML pages from route handlers using a template directory and a rendering context.
Public header
#include <vix.hpp>You can also include the app and template headers directly:
#include <vix/app/App.hpp>
#include <vix/template/Context.hpp>
#include <vix/view/TemplateView.hpp>What templates provide
Templates let a Vix application generate HTML responses from files.
Use templates for:
- HTML pages
- dashboards
- server-rendered views
- admin panels
- forms
- emails or HTML fragments
- dynamic pages with variables
Templates are configured with app.templates(...).
app.templates("views");Then handlers can call res.render(...).
res.render("index.html", ctx);Basic template setup
#include <vix.hpp>
int main()
{
vix::App app;
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});
app.run(8080);
return 0;
}Expected directory:
views/
index.htmlPublic alias
Vix Core exposes the template namespace as:
vix::tmplSo you can write:
vix::tmpl::Context ctx;instead of referencing the internal template namespace directly.
Configure the template directory
Use templates(...) on the app.
app.templates("views");This configures the root directory used to load template files.
Example:
views/
index.html
about.html
users/
show.htmlThen you can render:
res.render("index.html", ctx);
res.render("about.html", ctx);
res.render("users/show.html", ctx);Render a template
Use res.render(name, context).
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Welcome");
res.render("index.html", ctx);
});name is the template path relative to the template directory.
views/index.htmlis rendered with:
res.render("index.html", ctx);Template context
The context stores values passed to the template.
vix::tmpl::Context ctx;
ctx.set("title", "Home");
ctx.set("message", "Hello from Vix");Then render:
res.render("index.html", ctx);Render with route parameters
#include <vix.hpp>
int main()
{
vix::App app;
app.templates("views");
app.get("/users/{id}", [](vix::Request &req, vix::Response &res)
{
vix::tmpl::Context ctx;
ctx.set("title", "User profile");
ctx.set("user_id", req.param("id"));
res.render("users/show.html", ctx);
});
app.run(8080);
return 0;
}Request:
GET /users/42Template path:
views/users/show.htmlRender with query parameters
app.get("/search", [](vix::Request &req, vix::Response &res)
{
vix::tmpl::Context ctx;
ctx.set("title", "Search");
ctx.set("q", req.query_value("q", ""));
res.render("search.html", ctx);
});Request:
GET /search?q=vixRender from middleware-provided state
Middleware can store data in the request state.
struct CurrentUser
{
std::string id;
std::string name;
};Store the user:
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)res;
req.state().set(CurrentUser{"42", "Ada"});
next();
});Use it in a handler:
app.get("/me", [](vix::Request &req, vix::Response &res)
{
const auto &user = req.state().get<CurrentUser>();
vix::tmpl::Context ctx;
ctx.set("title", "My profile");
ctx.set("user_id", user.id);
ctx.set("user_name", user.name);
res.render("me.html", ctx);
});Check if templates are configured
Use has_views().
if (app.has_views())
{
vix::print("templates are configured");
}This is useful for advanced setup code or plugins.
Access the template view
Use views() to access the template rendering facade.
auto &view = app.views();If templates(...) was not called, views() throws.
if (app.has_views())
{
auto &view = app.views();
(void)view;
}Most applications do not need to access views() directly.
They use:
res.render("index.html", ctx);Templates and Response
res.render(...) is part of the public response helper.
res.render("index.html", ctx);It uses the template view configured by app.templates(...).
If templates are not configured, rendering fails.
Recommended:
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});Templates and static files
Templates and static files are different.
Use templates for dynamic HTML:
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});Use static files for assets:
app.static_dir("public/assets", "/assets");Common structure:
views/
index.html
public/
assets/
app.css
app.js
logo.svgTemplate with assets
Example app:
#include <vix.hpp>
int main()
{
vix::App app;
app.templates("views");
app.static_dir("public/assets", "/assets");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});
app.run(8080);
return 0;
}Template can reference assets like:
<link rel="stylesheet" href="/assets/app.css">
<script src="/assets/app.js"></script>Template page example
Example template file:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{{ message }}</p>
</body>
</html>Example handler:
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Welcome");
ctx.set("message", "Hello from Vix");
res.render("index.html", ctx);
});Multiple pages
#include <vix.hpp>
int main()
{
vix::App app;
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});
app.get("/about", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "About");
res.render("about.html", ctx);
});
app.run(8080);
return 0;
}Directory:
views/
index.html
about.htmlTemplates in route groups
Templates work normally inside route groups.
app.group("/admin", [](auto &admin)
{
admin.get("/dashboard", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Dashboard");
res.render("admin/dashboard.html", ctx);
});
});Route:
GET /admin/dashboardTemplate:
views/admin/dashboard.htmlTemplates with middleware
Middleware can prepare data for template handlers.
struct PageInfo
{
std::string app_name;
};Middleware:
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)res;
req.state().set(PageInfo{"Vix.cpp"});
next();
});Handler:
app.get("/", [](vix::Request &req, vix::Response &res)
{
const auto &page = req.state().get<PageInfo>();
vix::tmpl::Context ctx;
ctx.set("title", "Home");
ctx.set("app_name", page.app_name);
res.render("index.html", ctx);
});Templates and errors
If a template cannot be rendered, the route handler may throw.
For user-facing apps, you can catch errors and return a response.
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
try
{
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
}
catch (const std::exception &e)
{
res.status(500).text("Template error");
}
});Templates and JSON APIs
You can mix template pages and JSON APIs.
#include <vix.hpp>
int main()
{
vix::App app;
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});
app.get("/api/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"status", "ok"}
});
});
app.run(8080);
return 0;
}Templates and redirects
A template handler can redirect instead of rendering.
app.get("/dashboard", [](vix::Request &req, vix::Response &res)
{
const bool logged_in = req.has_header("Authorization");
if (!logged_in)
{
res.redirect("/login");
return;
}
vix::tmpl::Context ctx;
ctx.set("title", "Dashboard");
res.render("dashboard.html", ctx);
});Templates and status codes
Set the status before rendering.
app.get("/missing-page", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Not found");
res.status(404).render("404.html", ctx);
});Template lifecycle
The template lifecycle is:
App::templates
-> create FileSystemLoader
-> create template Engine
-> create TemplateView
-> route handler builds Context
-> ResponseWrapper::render
-> TemplateView renders response
-> Session writes HTTP responseRecommended directory layout
project/
src/
main.cpp
views/
index.html
about.html
errors/
404.html
public/
assets/
app.css
app.js
logo.svgExample setup:
app.templates("views");
app.static_dir("public/assets", "/assets");Complete example
#include <vix.hpp>
#include <string>
struct CurrentUser
{
std::string id;
std::string name;
};
int main()
{
vix::App app;
app.templates("views");
app.static_dir("public/assets", "/assets");
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)res;
req.state().set(CurrentUser{"42", "Ada"});
next();
});
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
ctx.set("message", "Hello from Vix");
res.render("index.html", ctx);
});
app.get("/me", [](vix::Request &req, vix::Response &res)
{
const auto &user = req.state().get<CurrentUser>();
vix::tmpl::Context ctx;
ctx.set("title", "Profile");
ctx.set("user_id", user.id);
ctx.set("user_name", user.name);
res.render("me.html", ctx);
});
app.get("/api/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"status", "ok"}
});
});
app.run(8080);
return 0;
}Directory:
views/
index.html
me.html
public/
assets/
app.cssAPI summary
| API | Purpose |
|---|---|
app.templates(directory) | Configure the template root directory. |
app.has_views() | Return whether templates are configured. |
app.views() | Access the template view facade. |
vix::tmpl::Context | Store values passed to templates. |
ctx.set(name, value) | Store a template variable. |
res.render(name, context) | Render a template response. |
app.static_dir(root, mount) | Serve static assets used by templates. |
Best practices
Configure templates before routes that render views.
app.templates("views");Keep templates in a dedicated directory.
views/Keep assets in a public directory.
public/assets/Mount assets under /assets.
app.static_dir("public/assets", "/assets");Build the context explicitly in the handler.
vix::tmpl::Context ctx;
ctx.set("title", "Home");Return immediately after redirects or errors.
if (!logged_in)
{
res.redirect("/login");
return;
}Use JSON routes for APIs and templates for pages.
app.get("/api/status", api_handler);
app.get("/", page_handler);Next steps
Read the next pages: