GitHub GitHub
docs / STE Filters

STE Filters

STE provides a rich set of built-in filters for transforming and formatting data in your templates. Apply them with the pipe operator:

{{ value | filterName }}
{{ value | filterName(arg1, arg2) }}

Filter Reference

abs

Converts a number to its absolute value.

{{ -42 | abs }} → 42

capitalize

Capitalises the first character of a string.

{{ "hello world" | capitalize }} → "Hello world"

chunk

Splits an array into sub-arrays of the specified size.

{{ [1,2,3,4,5] | chunk(2) }} → [[1,2],[3,4],[5]]
{{#set rows = products | chunk(3)}} {{#each rows}}
<div class="row">
    {{#each1 this}}
    <div class="col">{{this.name}}</div>
    {{/each1}}
</div>
{{/each}}

currency

Formats a number as currency. Defaults to $.

{{ 42.5 | currency }}      → "42.50 $"
{{ 42.5 | currency("€") }} → "42.50 €"

cycle

Creates a cycle through values. Use with next.

{{#set altClass = "alt" | cycle("odd", "even")}}
{{#each items}}
    <div class="{{ altClass | next }}">{{this}}</div>
{{/each}}

dateFormat

Formats a date. Default format: YYYY-MM-DD. The optional boolean parameter controls UTC (true, default) vs local time (false).

{{ date | dateFormat }}
→ "2024-02-14"

{{ date | dateFormat("DD/MM/YYYY HH:mm") }}
→ "14/02/2024 15:30"

{{ date | dateFormat("MMMM D, YYYY") }}
→ "February 14, 2024"

{{ date | dateFormat("h:mm a") }}
→ "3:30 pm"

Format Tokens

Token Output Description
YYYY / yyyy 2024 Full year
YY / yy 24 2-digit year
MMMM / mmmm February Full month name
MMM / mmm Feb Short month name
MM 02 Zero-padded month
M 2 Month number
DD / dd 09 Zero-padded day
D / d 9 Day number
dddd Wednesday Full weekday
ddd Wed Short weekday
HH / hh 08 Zero-padded 24h hour
H / h 8 24h hour
mm 05 Zero-padded minutes
m 5 Minutes
ss 09 Zero-padded seconds
s 9 Seconds
A AM / PM Uppercase meridiem
a am / pm Lowercase meridiem
Z +05:30 Timezone offset

Localisation

Pass a locale object as the fourth argument:

const frenchLocale = {
    monthNames: ["janvier", "février", "mars" /* ... */],
    monthNamesShort: ["janv", "févr", "mars" /* ... */],
    weekdayNames: ["dimanche", "lundi" /* ... */],
    weekdayNamesShort: ["dim", "lun" /* ... */],
}
// In template: {{ date | dateFormat("dddd D MMMM YYYY", false, frenchLocale) }}
// → "mercredi 14 février 2024"

defaults

Returns the first non-null, non-undefined value.

{{ null | defaults(undefined, "", "fallback") }} → "fallback"

dump

Pretty-prints a value as JSON. Useful for debugging.

{{ object | dump }}

escape

Escapes HTML special characters.

{{ "<div>" | escape }} → "&lt;div&gt;"

fileSize

Converts bytes to a human-readable size.

{{ 1024 | fileSize }}    → "1 KB"
{{ 1048576 | fileSize }} → "1 MB"

first

Returns the first element of an array or first character of a string.

{{ [1, 2, 3] | first }} → 1
{{ "hello" | first }}   → "h"

groupBy

Groups an array of objects by a key. Supports dot and bracket notation for nested properties.

{{ users | groupBy("country") }}
{{ posts | groupBy("frontmatter.category") }}
{{ data | groupBy("metadata['group-id']") }}

has

Checks if a value exists in an array, object, or string.

{{ object | has("property") }}      → true/false
{{ "hello world" | has("world") }}  → true

int

Converts a value to an integer.

{{ "42.9" | int }} → 42

join

Joins array elements with a separator. Optional second argument sets the last separator.

{{ ["a", "b", "c"] | join(", ") }}           → "a, b, c"
{{ ["a", "b", "c"] | join(", ", " and ") }}  → "a, b and c"

last

Returns the last element of an array or last character of a string.

{{ [1, 2, 3] | last }} → 3
{{ "hello" | last }}   → "o"

length

Returns the length of a string, array, or number of keys in an object.

{{ "hello" | length }}   → 5
{{ [1, 2, 3] | length }} → 3

log

Logs a value to the console and returns it unchanged. For debugging.

{{ value | log("label") }}

lowercase

{{ "HELLO" | lowercase }} → "hello"

next

Advances and returns the next value in a cycle.

{{ cycleId | next }}

numberFormat

Formats large numbers with suffixes.

{{ 1500000 | numberFormat }} → "1.5M"

preserveSpaces

Converts spaces to &nbsp; entities for HTML rendering.

{{ "hello   world" | preserveSpaces }}

range

Checks if a number is within a range. Third boolean argument makes it inclusive.

{{ 5 | range(1, 10) }}         → true
{{ 15 | range(1, 10) }}        → false
{{ 20 | range(20, 30, true) }} → true

removeSpaces

Removes all whitespace from a string.

{{ "hello world" | removeSpaces }} → "helloworld"

replace

Replaces all occurrences of a substring.

{{ "hello world" | replace("world", "there") }} → "hello there"

reverse

Reverses a string or array.

{{ "hello" | reverse }}  → "olleh"
{{ [1,2,3] | reverse }}  → [3,2,1]

round

Rounds to the specified number of decimal places.

{{ 3.14159 | round(2) }} → 3.14

safeStringify

Safely converts an object to JSON, replacing circular references with "[Circular]".

{{ complexObject | safeStringify }}

skip

Skips the first N elements (positive) or last N elements (negative).

{{ [10,20,30,40] | skip(2) }}  → [30, 40]
{{ [10,20,30,40] | skip(-2) }} → [10, 20]
{{#set regularPosts = posts | skip(1)}} {{#set page3 = allItems | skip(20) | take(10)}}

slice

Returns a portion of an array between start and end indices. Supports negative indices.

{{ [10,20,30,40,50] | slice(1, 3) }}   → [20, 30]
{{ [10,20,30,40,50] | slice(-3, -1) }} → [30, 40]
{{ [10,20,30,40,50] | slice(2) }}      → [30, 40, 50]
{{#set pageItems = allItems | slice(pageStart, pageEnd)}} {{#set lastThree = items | slice(-3)}}

slugify

Converts a string to a URL-friendly slug.

{{ "Hello World!" | slugify }} → "hello-world"

sortBy

Sorts an array of objects by a key. Default order is "asc". Supports nested properties.

{{ users | sortBy("name") }}
{{ users | sortBy("name", "desc") }}
{{ posts | sortBy("frontmatter.date", "desc") }}

sortByDate

Sorts an array of objects by a date field. Ensures proper date comparison.

{{ posts | sortByDate("date") }}
{{ posts | sortByDate("frontmatter.publish_date", "desc") }}

take

Returns the first N elements (positive) or last N elements (negative).

{{ [10,20,30,40] | take(2) }}  → [10, 20]
{{ [10,20,30,40] | take(-2) }} → [30, 40]
{{#set featured = posts | take(3)}} {{#set recent = comments | take(-5)}} {{#set topRated = products | sortBy("rating",
"desc") | take(4)}}

timeAgo

Converts a date to a relative time string.

{{ date | timeAgo }} → "2 hours ago"

Creates an HTML link.

{{ "https://example.com" | toLink("Visit") }}
→ '<a href="https://example.com">Visit</a>'

{{ "https://example.com" | toLink("Visit", true, true) }}
→ '<a href="https://example.com" target="_blank" rel="external noopener noreferrer">Visit</a>'

trim

Removes whitespace from both ends of a string.

{{ "  hello  " | trim }} → "hello"

truncate

Truncates to a character limit, appending "...".

{{ "Long text here" | truncate(5) }} → "Long..."

truncateWords

Truncates to a word limit.

{{ "The quick brown fox" | truncateWords(2) }} → "The quick..."

type

Returns the JavaScript type of a value.

{{ value | type }} → "string", "number", "object", etc.

uppercase

{{ "hello" | uppercase }} → "HELLO"

where

Filters an array of objects by a property value. Supports nested properties.

{{ users | where("active", true) }}
{{ posts | where("frontmatter.published", true) }}

wordCount

Counts words in a string.

{{ "hello world" | wordCount }} → 2

Filter Chaining

Pipe multiple filters together — the output of each becomes the input for the next:

{{ "HELLO WORLD" | lowercase | capitalize }}
→ "Hello world"

{{ [1,2,3] | reverse | join(", ") }}
→ "3, 2, 1"

{{ user.name | defaults("Anonymous") | uppercase }}
→ "ANONYMOUS"

{{ items | where("active", true) | sortBy("date") | take(10) }}

Performance Guide

By filter complexity

Category Filters Complexity Safe up to
High performance slice, take, skip, chunk O(n) 10,000+ items
Moderate sortBy, groupBy, where O(n) to O(n log n) ~1,000 items

Recommended chaining order

<!-- ✅ Filter first, then sort the smaller result -->
{{#set result = items | where("status", "active") | sortBy("date") | take(10)}}

<!-- ❌ Sorting everything before filtering is wasteful -->
{{#set result = items | sortBy("date") | where("status", "active") | take(10)}}

Server-side vs template filters

Operation Small (<100) Medium (100–1k) Large (1k+)
Pagination Either slice in template Server-side
Sorting Either sortBy in template Server-side
Filtering Either where in template Server-side
Grouping Either groupBy in template Server-side
Taking/Skipping Template Template Either
Chunking Template Template Template

Rule of thumb: if the operation would take over 100ms, move it to the server.