Skip to main content

Pebble Functions

A set of utility functions registered by Invirt that can be used inside Pebble templates.

request()​

Returns the current http4k Request (wrapped in an InvirtRequest). This function is required inside macros, where the context request object is not visible. Outside macros either form works.

{% macro requestSummary() %}
{{ request().uri }}
{{ request().method }}
{% endmacro %}

{{ request.method }}
{{ request.query("q") }}

errors()​

Returns the validation errors object (io.validk.ValidationErrors), or null if there are no validation errors for the current request. Required inside macros — outside, the errors context object is equivalent.

Read more about validation here.

{% if errors().hasErrors("name") %}
<div class="text-error">{{ errors().error("name") }}</div>
{% endif %}

json(value)​

Renders the given object as a JSON string. Typically used when embedding model data into a JavaScript context.

<div id="map" data-map-place='{{ json(model.place) | raw }}'></div>

jsonArray(value)​

Same as json(), but always renders the value as a JSON array. When value is not a collection it is wrapped in a single-element array.

<div id="map" data-map-places='{{ jsonArray(model.places) | raw }}'></div>

uuid()​

Returns a new time-ordered UUIDv7 as a hex string (no dashes). Convenient for unique DOM ids in templates.

<input type="text" id="field-{{ uuid() }}"/>

currencyFromMinorUnit(minorUnitAmount, currency)​

Formats a minor-unit currency value (pence/cents) as a human-readable string using the currency's symbol and default fraction digits.

{{ currencyFromMinorUnit(order.totalMinorUnit, "GBP") }} // £12.50

pluralize(count, singular, plural)​

Returns singular when count == 1 and plural otherwise.

You have {{ model.count }} {{ pluralize(model.count, "message", "messages") }}.

dateRange(from, to)​

Renders a pair of LocalDates as one phrase that says each part only once: a null to (how a single-day entry is modelled) or a to equal to from is that one day, a range inside one calendar year carries the year on its closing date alone, and a range crossing years spells both out. Both ends carry the English ordinal suffix on the day of month.

{{ dateRange(model.openFrom, model.openTo) }}
{# → "5th November – 5th December 2026" #}

{{ dateRange(model.openFrom, null) }}
{# → "5th November 2026" #}

A from that is not a LocalDate, or a to that is neither a LocalDate nor null, is a template bug and fails rather than rendering something plausible. The phrasing is formatDateRange's default; a template that needs another pattern formats the range in Kotlin and passes the string in its model.

dateWithDaySuffix filter​

Formats a LocalDate, LocalDateTime or Instant using a DateTimeFormatter pattern, inserting the English ordinal suffix on the day of month (1st, 2nd, 3rd, ...).

{{ model.deliveryDate | dateWithDaySuffix("EEEE, MMMM d yyyy") }}
{# → "Sunday, March 1st 2026" #}

An Instant is a point on the timeline rather than a calendar date, so it takes a zone argument (a zone id) saying which zone the date is read in, and the filter fails if it is missing. 2026-08-31T23:02:00Z is the 31st of August in UTC and the 1st of September in Europe/London, so there is no zone the filter could pick for you that isn't the wrong day for someone.

{{ model.dispatchedAt | dateWithDaySuffix("EEEE, MMMM d yyyy", zone="Europe/London") }}
{# → "Tuesday, September 1st 2026" #}

zone means nothing to a LocalDate or a LocalDateTime, which are calendar values already, and is ignored if passed.