Components
Components are the building blocks of PyTemplate applications. They allow you to create reusable, encapsulated pieces of UI with their own logic and styling.
Component Definition
Components are defined using the component keyword followed by a name and optional props parameter:
component ComponentName(props) {
<template>
<!-- Your template content here -->
</template>
}Props
Props allow you to pass data into components. Access props using the props.get() method:
component Label(props) {
<template>
<span class="text-red bg-black">
{{ str(sqrt(int(props.get("count", "1")))) }}
</span>
<span>{{ props.get("text", "Click Me") }}</span>
</template>
}Props.get() Method
- Syntax:
props.get(key, default_value) - Parameters:
key: The property name to retrievedefault_value: Value to return if the key doesn't exist
- Returns: The prop value or default value
Component Usage
Use components with the @ syntax and pass props as a dictionary:
@Label({ "count": 4, "text": "Button" })Example from Demo
component Button(props) {
<template>
<button onclick="{{ props.get("onclick", "") }}" class="demo-button">
@Label({
"count": {{ props.get("count", 4) }},
"text": {{ props.get("label", "Button") }}
}) {
@slot()
}
</button>
</template>
}Slots
Slots allow you to pass content into components. Use @slot() to render the content passed between component tags:
component Button(props) {
<template>
<button>
@Label({ "count": {{ props.get("count", 4) }}, "text": {{ props.get("label", "Button") }} }) {
@slot() <!-- This renders the content passed to the component -->
}
</button>
</template>
}
<!-- Usage with slot content -->
@Button({ "onclick": "toggleCount()", "label": "Toggle", "count": {{ str(count * count) }} }) {
Toggle Count <!-- This content goes into @slot() -->
}Complex Component Example
Here's a more complex component from the demo:
component TodoItem(props) {
<template>
<li class="todo-item">
if props.get("done", False) {
<input type="checkbox" checked="true" />
} else {
<input type="checkbox" />
}
if props.get("done", False) {
<span class="completed">
{{ props.get("text", "Todo item") }}
</span>
} else {
<span>
{{ props.get("text", "Todo item") }}
</span>
}
@Label({ "count": {{ props.get("priority", 1) }} }) { Priority }
</li>
</template>
}Component Composition
Components can be nested and composed together:
component App() {
<template>
<div class="demo-container">
<h1>Template Engine Demo</h1>
@Button({
"onclick": "showAlert('Hello World!')",
"label": "Alert",
"count": 64
}) {
Show Alert
}
<div class="todo-list">
<ul>
for todo in todos {
@TodoItem({
"text": {{ todo["text"] }},
"done": {{ todo["done"] }},
"priority": {{ todo["priority"] }}
})
}
</ul>
</div>
</div>
</template>
}Best Practices
- Use descriptive component names that clearly indicate their purpose
- Provide default values for all props using
props.get(key, default) - Keep components focused on a single responsibility
- Use slots for flexible content injection
- Compose components to build complex UIs from simple building blocks
Component Lifecycle
Components in PyTemplate are stateless by design. Each time a component is rendered, it receives fresh props and renders accordingly. This makes components predictable and easy to reason about.
Styling Components
You can include CSS styles within your components or in separate style blocks:
component StyledComponent(props) {
<template>
<div class="my-component">
<h2>{{ props.get("title", "Default Title") }}</h2>
<p>{{ props.get("content", "Default content") }}</p>
</div>
</template>
<style>
.my-component {
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
}
</style>
}