Template Inclusion and Composition
Build complex UIs by composing small, focused templates together.
Basic Inclusion
Include one template inside another with {{> templateName}}:
Passing Data
Data Context
Pass a data context to the included template:
The included template receives the passed data as its data context:
Multiple Arguments
Passing the Current Context
Dynamic Templates
Render different templates based on reactive data:
ts
Template.app.helpers({
currentView() {
const route = Router.current();
switch (route) {
case 'home':
return 'homePage';
case 'profile':
return 'profilePage';
case 'settings':
return 'settingsPage';
default:
return 'notFoundPage';
}
},
viewData() {
return { userId: Router.param('id') };
},
});Dynamic Component Pattern
ts
Template.widgetRenderer.helpers({
widgets() {
return [
{ type: 'chartWidget', config: { chartType: 'bar', data: salesData } },
{ type: 'statsWidget', config: { metrics: ['users', 'revenue'] } },
{ type: 'tableWidget', config: { collection: 'orders', limit: 10 } },
];
},
});Content Blocks
Templates can accept block content, similar to "slots" in other frameworks.
Defining a Wrapper Template
Using the Wrapper
Else Content
Templates can also accept an elseBlock:
Layout Pattern
Build a layout system with content blocks:
Recursive Templates
Templates can include themselves for tree structures:
File Tree Example
Reusable Component Library
Button Component
Usage:
Modal Component
Usage:
Form Field Component
Usage:
Best Practices
- Keep templates small — each template should do one thing well
- Name clearly — use descriptive names like
userCard,taskListItem,modalConfirm - Pass only needed data — don't pass entire objects when only a few fields are used
- Use named iteration — prefer
{{#each item in list}}over{{#each list}} - Compose, don't duplicate — extract shared patterns into reusable templates
- Document data contracts — comment what data each template expects