AppML Templates — Customizing HTML Output with Themes and Layouts
In this tutorial, you will learn about AppML Templates. We cover key concepts, practical examples, and best practices to help you master this topic.
AppML templates let you override the default HTML output with custom layouts, branding, and styling, turning generated data interfaces into polished, branded applications.
What You'll Learn
You will create custom templates for AppML views, override default layouts, apply CSS themes, and build a consistent brand experience across your generated applications.
Why It Matters
Default AppML views are functional but generic. Custom templates let you match your brand colors, layout, and component styles while keeping the automatic data binding and CRUD functionality.
Real-World Use
DodaZIP's configuration portal uses custom AppML templates styled to match the Durga Antivirus Pro design system. Users cannot tell the AppML-generated pages are running on a different framework.
flowchart LR
A[AppML View] --> B{Template Resolver}
B --> C[Custom Template]
B --> D[Default Template]
C --> E[Branded HTML]
D --> F[Standard HTML]
style A fill:#1e293b,color:#fff
style C fill:#0f172a,color:#fff
Template Directory Structure
Custom templates are stored in the templates directory of your AppML installation.
templates/
default/
list.html
detail.html
grid.html
form.html
custom/
list.html
detail.html
my-theme/
list.html
detail.html
Each template is an HTML file with placeholders where AppML injects data.
Custom List View Template
Create a custom template for list views with a header and custom table structure.
<div class="appml-list">
<div class="list-header">
<h2>{{view.title}}</h2>
<div class="list-actions">
{{search}}
{{add_button}}
</div>
</div>
<table class="data-table">
<thead>
<tr>
{% for column in columns %}
<th>{{column.header}}</th>
{% endfor %}
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for column in columns %}
<td>{{row[column.field]}}</td>
{% endfor %}
<td class="actions">
{{row.edit_button}}
{{row.delete_button}}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{{pagination}}
</div>
Expected output: A custom-styled data table with a branded header, search bar, and action buttons.
Reference the custom template in the view definition:
<view type="list" table="employees" template="custom/list.html">
...
</view>
Custom Detail View Template
Create a two-column form layout for detail views.
<div class="appml-detail">
<h2>{{view.title}}</h2>
<form class="two-column-form" method="post">
<div class="form-column">
{% for field in fields[:half] %}
<div class="form-group">
<label>{{field.label}}</label>
{{field.input}}
{{field.error}}
</div>
{% endfor %}
</div>
<div class="form-column">
{% for field in fields[half:] %}
<div class="form-group">
<label>{{field.label}}</label>
{{field.input}}
{{field.error}}
</div>
{% endfor %}
</div>
<div class="form-actions">
{{save_button}}
{{cancel_button}}
</div>
</form>
</div>
Expected output: A two-column form layout with evenly distributed fields.
Global Theme Template
Override the default layout wrapper for consistent branding across all views.
<!DOCTYPE html>
<html>
<head>
<title>{{page.title}} - DodaTech Admin</title>
<link rel="stylesheet" href="/static/css/admin-theme.css">
{{head_extra}}
</head>
<body>
<nav class="sidebar">
<div class="brand">
<img src="/static/img/logo.svg" alt="DodaTech">
</div>
{{navigation}}
</nav>
<main class="content">
{{flash_messages}}
{{content}}
</main>
{{scripts}}
</body>
</html>
Expected output: Every AppML page renders inside the branded layout with sidebar navigation.
Configure the global template in appml.config.json:
{
"theme": {
"layout": "templates/admin/layout.html"
}
}
Conditional Rendering
Templates support conditional sections for showing or hiding elements based on data.
<div class="status-badge {{row.status | lower}}">
{{row.status}}
</div>
{% if row.priority == 'high' %}
<span class="priority-flag">Requires attention</span>
{% endif %}
Expected output: Status badges with color classes based on the status value. High-priority items show an additional flag.
Common Mistakes
Editing default templates directly: Changes to default templates are lost during AppML updates. Always create custom templates in a separate directory.
Forgetting to include required placeholders: Omitting {{pagination}}, {{search}}, or {{flash_messages}} breaks functionality. Always include core placeholders.
Hardcoding database field names in templates: Use the field references from the model instead. Hardcoded names break when the model changes.
Not testing templates with different data states: A template that works with 10 records may break with empty data sets. Test with zero records and error states.
Overengineering templates with complex logic: Templates handle presentation, not business logic. Complex conditions belong in the controller layer.
Practice Questions
- Where are custom AppML templates stored?
In a templates directory relative to the AppML runtime, organized into subdirectories by theme name.
- How do you reference a custom template in a view definition?
Use the
templateattribute on the view element:template="custom/list.html".
- What placeholder renders the search box in a list view template?
The
{{search}}placeholder.
- How do you create a global theme applied to all views?
Configure the layout template in appml.config.json under the theme section.
- What happens to custom templates when you update AppML?
Default templates are overwritten. Custom templates in separate directories are preserved.
Challenge
Create a complete custom theme for an AppML application that includes a sidebar navigation, branded header, custom list view with striped rows, and a two-column detail form. Apply the theme globally to all views.
Frequently Asked Questions
Mini Project
Design a complete branded dashboard theme for an inventory management system. Include a custom list template with product images, a detail template with tabs for different information sections, and a grid template for category browsing.
What's Next
Continue to AppML Forms to learn how to customize form layouts, add validation, and create complex data entry interfaces.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro