Templates
STX provides a powerful templating system with an intuitive syntax that makes building UIs both productive and enjoyable. This page covers all template features and capabilities available in the STX ecosystem.
Template Syntax
Text Interpolation
STX uses double curly braces for safe text interpolation:
html
<div>{{ message }}</div>
<span>{{ user.name }}</span>
<p>{{ formatDate(post.createdAt) }}</p>
Raw HTML Interpolation
For trusted HTML content, use triple braces:
html
<div>{{{ trustedHtmlContent }}}</div>
Attribute Binding
Bind dynamic values to attributes:
html
<img :src="imageUrl" :alt="imageAlt">
<button :disabled="isLoading" :class="buttonClass">
<input :value="inputValue" :placeholder="placeholderText">
Conditional Rendering
Basic Conditionals
html
@if(user.isAuthenticated)
<dashboard />
@elseif(user.isGuest)
<welcome-message />
@else
<login-form />
@endif
Short Conditionals
html
@auth
<admin-panel />
@endauth
@guest
<login-banner />
@endguest
@unless(user.hasPermission)
<access-denied />
@endunless
Conditional Classes
html
<div class="card" :class="{
'card--active': isActive,
'card--disabled': isDisabled,
'card--large': size === 'large'
}">
Content
</div>
List Rendering
Basic Loops
html
@foreach(items as item)
<div class="item">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}</p>
</div>
@endforeach
Loop with Index
html
@foreach(users as index => user)
<tr class="{{ index % 2 === 0 ? 'even' : 'odd' }}">
<td>{{ index + 1 }}</td>
<td>{{ user.name }}</td>
</tr>
@endforeach
Empty State
html
@forelse(posts as post)
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.excerpt }}</p>
</article>
@empty
<p>No posts found.</p>
@endforelse
Nested Loops
html
@foreach(categories as category)
<div class="category">
<h2>{{ category.name }}</h2>
@foreach(category.products as product)
<div class="product">
<h3>{{ product.name }}</h3>
<p>${{ product.price }}</p>
</div>
@endforeach
</div>
@endforeach
Template Composition
Layouts
html
<!-- layouts/app.stx -->
<!DOCTYPE html>
<html>
<head>
<title>@yield('title', 'Default Title')</title>
@stack('styles')
</head>
<body>
<header>
@include('partials.navigation')
</header>
<main>
@yield('content')
</main>
<footer>
@include('partials.footer')
</footer>
@stack('scripts')
</body>
</html>
Template Inheritance
html
<!-- pages/home.stx -->
@extends('layouts.app')
@section('title', 'Welcome Home')
@push('styles')
<link rel="stylesheet" href="/css/home.css">
@endpush
@section('content')
<h1>Welcome to our website!</h1>
<p>This is the home page content.</p>
@endsection
@push('scripts')
<script src="/js/home.js"></script>
@endpush
Partial Templates
html
<!-- partials/user-card.stx -->
<div class="user-card">
<img :src="user.avatar" :alt="user.name">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</div>
<!-- Usage -->
@include('partials.user-card', { user: currentUser })
Template Directives
Form Handling
html
<form @submit.prevent="handleSubmit">
<input @model="form.email" type="email" required>
<input @model="form.password" type="password" required>
<button type="submit" :disabled="isSubmitting">
{{ isSubmitting ? 'Logging in...' : 'Login' }}
</button>
</form>
Event Handling
html
<button @click="increment">Increment</button>
<input @input="handleInput" @blur="validateField">
<div @mouseenter="showTooltip" @mouseleave="hideTooltip">
Hover me
</div>
<!-- Event modifiers -->
<form @submit.prevent="onSubmit">
<input @keyup.enter="search">
<button @click.once="initializeOnce">
Dynamic Binding
html
<component :is="currentComponent" :props="componentProps" />
<input :[attributeName]="attributeValue">
<button @[eventName]="eventHandler">
Template Optimization
Template Compilation
STX compiles templates to optimized JavaScript:
typescript
// Original template
const template = `
@foreach(items as item)
<div>{{ item.name }}</div>
@endforeach
`
// Compiled output (simplified)
function render(context) {
let html = ''
for (const item of context.items) {
html += `<div>${escape(item.name)}</div>`
}
return html
}
Template Caching
typescript
// Template caching configuration
const templateConfig = {
cache: {
enabled: true,
ttl: 3600, // 1 hour
invalidateOnChange: true
},
// Precompile templates
precompile: [
'layouts/**/*.stx',
'components/**/*.stx',
'pages/**/*.stx'
]
}
Lazy Loading
html
<!-- Lazy load heavy components -->
<suspense>
<template #default>
<heavy-component @lazy />
</template>
<template #fallback>
<loading-spinner />
</template>
</suspense>
Template Security
Automatic Escaping
STX automatically escapes output to prevent XSS:
html
<!-- Safe: automatically escaped -->
<div>{{ userInput }}</div>
<!-- Raw HTML: only for trusted content -->
<div>{{{ trustedContent }}}</div>
Content Security Policy
typescript
// CSP-compliant templates
const cspConfig = {
nonce: generateNonce(),
inlineStyles: false,
inlineScripts: false
}
// Templates automatically include nonce
<script nonce="{{ cspNonce }}">
// Safe inline script
</script>
Advanced Features
Template Slots
html
<!-- components/modal.stx -->
<div class="modal">
<header class="modal__header">
<slot name="header">Default Header</slot>
</header>
<main class="modal__body">
<slot>Default content</slot>
</main>
<footer class="modal__footer">
<slot name="footer">
<button @click="close">Close</button>
</slot>
</footer>
</div>
<!-- Usage -->
<modal>
<template #header>
<h2>Custom Header</h2>
</template>
<p>Modal content goes here</p>
<template #footer>
<button @click="save">Save</button>
<button @click="cancel">Cancel</button>
</template>
</modal>
Scoped Slots
html
<!-- components/data-list.stx -->
<div class="data-list">
@foreach(items as item, index)
<slot :item="item" :index="index">
<!-- Default item template -->
<div class="item">{{ item.name }}</div>
</slot>
@endforeach
</div>
<!-- Usage with custom template -->
<data-list :items="users">
<template #default="{ item, index }">
<div class="user-item">
<span>{{ index }}.</span>
<strong>{{ item.name }}</strong>
<small>{{ item.email }}</small>
</div>
</template>
</data-list>
Template Macros
html
<!-- Define reusable template macros -->
@macro('button', { type = 'button', size = 'medium', variant = 'primary' })
<button
type="{{ type }}"
class="btn btn--{{ variant }} btn--{{ size }}"
{{ $attributes }}
>
{{ $slot }}
</button>
@endmacro
<!-- Usage -->
@button({ variant: 'secondary', size: 'large' })
Click me
@endbutton
Template Testing
Template Unit Tests
typescript
import { renderTemplate } from '@stx/testing'
test('user list template', () => {
const template = `
@foreach(users as user)
<div class="user">{{ user.name }}</div>
@endforeach
`
const context = {
users: [
{ name: 'John Doe' },
{ name: 'Jane Smith' }
]
}
const html = renderTemplate(template, context)
expect(html).toContain('<div class="user">John Doe</div>')
expect(html).toContain('<div class="user">Jane Smith</div>')
})
Snapshot Testing
typescript
test('component template snapshot', () => {
const component = renderComponent('UserCard', {
user: { name: 'John', email: 'john@example.com' }
})
expect(component.html()).toMatchSnapshot()
})
Related Resources
- Template Syntax Guide - Comprehensive template syntax guide
- Component System - Building reusable components
- Directives - Custom template directives
- Performance - Template performance optimization