Templating Using template features in Semantic UI Guide
Categories

Templating

Overview

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.

Writing Templates

Flexible Syntax

Template syntax is designed to be adaptable to your team’s preferences and to help components feel more natural across codebases of different languages.

Brackets

Bracket syntax supports either single or double bracket as long as it is consistent across the file.

Single Bracket
Welcome, { getFirstName }
Double Bracket
Welcome, {{ getFirstName }}

Expression Styles

Expressions support both Lisp-style (semantic) and JavaScript syntax, even mixed in the same template:

Semantic (Lisp-style)
{ formatDate date 'h:mm a' timezone }
{ titleCase concat firstName ' ' lastName }
JavaScript
{ formatDate(date, 'h:mm a', timezone) }
{ users.filter(u => u.active).length }
Mixed Styles
{ 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.

Binding Data

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.

Template Features

Expressions

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}

Attribute Expressions

With quotes: always renders as string

<input type="number" value="{count}">

Without quotes: removes attribute when falsy

<button disabled={isLoading}>Submit</button>

Conditionals

Control flow using #if, #else if, and #else.

{#if isColor 'red'}
Red
{else if isColor 'blue'}
Blue
{else}
Another color
{/if}

Loops

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}

Async Operations

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.

Reactivity Control

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}

Slots

Define areas for external content injection.

Default slot

{>slot}

Named slot

{>slot header}

Global Helpers

Built-in utilities for formatting, logic, and CSS classes:

{formatDate createdAt 'MMM DD, YYYY'}
{capitalize title}
{classIf isActive 'active' 'inactive'}
{hasAny items}

Custom Helpers

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`;
});

Subtemplates

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
}

Template as Settings

Let consumers provide custom templates:

// Consumer specifies template
$('ui-table').settings({
rowTemplate: myCustomRowTemplate
});

Snippets

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'}
Previous
Key Bindings
Next
Expressions