
Enter a search term above to see results...
Enter a search term above to see results...
Semantic UI templates compile to an Abstract Syntax Tree (AST) for efficient rendering and targeted DOM updates. The declarative syntax handles async operations, loops, conditionals, and reactive expressions with automatic dependency tracking.
Template syntax is designed to be adaptable to your team’s preferences and to help components feel more natural across codebases of different languages.
Bracket syntax supports either single or double bracket as long as it is consistent across the file.
Welcome, { getFirstName }
Welcome, {{ getFirstName }}
Expressions support both Lisp-style (semantic) and JavaScript syntax, even mixed in the same template:
{ formatDate date 'h:mm a' timezone }{ titleCase concat firstName ' ' lastName }
{ formatDate(date, 'h:mm a', timezone) }{ users.filter(u => u.active).length }
{ formatDate (date + offset) 'h:mm a' {locale: 'en-US'} }
Templates compile once per component type and reuse the AST across instances. See Templates & Data Context for integration details.
Templates are bound to a data context which is used for evaluating expressions.
You can think of the data context as “all the variables defined in the scope of your template”.
When using the component framework these will come from sources in your component like their settings, and internal state.
Evaluate against the template’s data context. Expressions are reactive - they re-evaluate when signals change.
{name}{users.0.email}{formatDate createdAt 'MMM DD'}{#html sanitizedContent}
With quotes: always renders as string
<input type="number" value="{count}">
Without quotes: removes attribute when falsy
<button disabled={isLoading}>Submit</button>
Control flow using #if
, #else if
, and #else
.
{#if isColor 'red'} Red{else if isColor 'blue'} Blue{else} Another color{/if}
Three iteration syntaxes with automatic index
/key
variables:
Direct context
{#each users} {name} ({index}){/each}
Named iterator (each…in)
{#each user in users} {user.name} ({index}){/each}
Alternate syntax (each…as)
{#each users as user, idx} {user.name} ({idx}){/each}
Object iteration
{#each value, key in settings} {key}: {value}{/each}
Empty state
{#each items} {name}{else} No items{/each}
Handle promises directly in templates with automatic reactive re-execution:
{#async fetchUser userId as user} <h3>{user.name}</h3>{loading} <div class="spinner">Loading...</div>{error as e} <p>Failed: {e.message}</p>{/async}
Reactive dependencies (userId
above) trigger automatic refetch.
Fine-tune when template sections update:
Force re-evaluation including non-reactive content
{#rerender userId} <p>User: {userName}</p> <p>Timestamp: {getTimestamp}</p>{/rerender}
Only re-render when computed value changes
{#guard getUserStatus} <div class="status-{getUserStatus}"> {expensiveComputation} </div>{/guard}
Define areas for external content injection.
Default slot
{>slot}
Named slot
{>slot header}
Built-in utilities for formatting, logic, and CSS classes:
{formatDate createdAt 'MMM DD, YYYY'}{capitalize title}{classIf isActive 'active' 'inactive'}{hasAny items}
Extend the template system:
import { registerHelper } from '@semantic-ui/templating';
registerHelper('timeAgo', (date) => { const seconds = Math.floor((Date.now() - date) / 1000); if (seconds < 60) return 'just now'; if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`; return `${Math.floor(seconds / 3600)}h ago`;});
Compose components and enable template-as-settings patterns:
Simple subtemplate
{> userCard user}
With data object
{> userCard name=user.name role='admin'}
Dynamic template selection
{>template name=getTemplateName data={user: currentUser}}
Separate reactive/non-reactive data
{>template name='userProfile' reactiveData={status: userStatus} // Re-renders on change data={theme: 'dark'} // Static data}
Let consumers provide custom templates:
// Consumer specifies template$('ui-table').settings({ rowTemplate: myCustomRowTemplate});
Inline reusable fragments - like subtemplates but defined in the same file:
{#snippet userRow} <tr> <td>{name}</td> <td>{role}</td> <td>{formatDate joinDate 'MMM YYYY'}</td> </tr>{/snippet}
Use multiple times with different data
{#each admins} {>userRow}{/each}
{#each members} {>userRow}{/each}
Snippets inherit parent data context but can receive additional data:
{>userRow extraClass='highlight'}