twig.js Compatibility
The addon ships several shims and compile-time patches that make PHP Twig templates work in the browser via twig.js 1.x.
Automatic patches
These are applied automatically — no configuration needed.
random() shim
twig.js does not implement random(). The addon registers a shim via extendFunction that matches PHP Twig's behavior:
| Argument | Returns |
|---|---|
random(n) | Random integer between 0 and n (inclusive) |
random(array) | Random element from the array |
random(string) | Random character from the string |
random() | Random 7-character alphanumeric string |
Commonly used in patterns to generate unique DOM IDs for accordion, tabs, and modal components.
Arrow-function |filter
PHP Twig 3.x added arrow-function syntax to |filter:
{{ items|filter(v => v) }}twig.js cannot parse =>. The addon preprocesses templates before registration, replacing |filter(v => v) with a custom |filter_truthy filter that removes falsy values from arrays.
function('php_fn')
PHP Twig's function() calls a PHP function by name at render time. twig.js looks for a registered function called function (the literal word), which doesn't exist, and throws an error.
The addon preprocesses templates to replace function('any_name') with '' (empty string), which allows surrounding |default(...) filters to activate correctly.
Short-ternary patch
twig.js 1.x has a runtime bug with short ternaries (a ? b without an else branch). The operator always pops 3 values from the stack, but a short ternary only pushes 2, causing either a crash ("Expected end of array") or a silently wrong value.
The addon applies a two-part patch via Twig.extend():
- Compile-time: marks
?tokens as short-ternary when no:follows - Runtime: pops only 2 values for short-ternary tokens
{% import _self %} macro hoisting
PHP Twig compiles macros before any output code runs, so they're available throughout a template regardless of source order. twig.js evaluates tokens sequentially — if {% import _self as X %} appears before the macro definitions, X is an empty object.
The addon hoists all {% macro %}...{% endmacro %} blocks to the top of any template that uses {% import _self %}, ensuring macros are registered before the import runs.
source() function
PHP Twig's source() reads a file and returns its raw content. The addon implements it as:
- Checks
window.__svgSourceRegistry— a build-time registry populated viaimport.meta.globin yourpreview.ts(useful for inline SVGs) - Falls back to a synchronous XHR request for paths served via Storybook's
staticDirs - Returns
''on error (network error, cross-origin, 404) — no throw
For SVG spritemap use, populate the registry in your preview.ts:
// .storybook/preview.ts
const svgFiles = import.meta.glob('/path/to/svg/*.svg', { query: '?raw', eager: true });
(window as any).__svgSourceRegistry = Object.fromEntries(
Object.entries(svgFiles).map(([path, mod]) => [
`/svg/${path.split('/').pop()}`,
(mod as { default: string }).default
.replace(/<\?xml[^?]*\?>/g, '')
.replace(/<!--[\s\S]*?-->/g, '')
.trim(),
])
);Known limitations
{% apply %}tag — not supported by twig.js. Avoid in pattern templates.- Timber-specific filters (
|timber_image,|get_src_from_attachment_id, etc.) — these are PHP-only and will throw errors if called in templates. Guard with{% if image %}checks or use|default. - PHP functions via
function()— only no-argumentfunction('name')calls are patched. Complex expressions likefunction('fn', arg)are not handled. {% cache %}/{% spaceless %}— twig.js 1.x does not support all PHP Twig 3.x tags. Test patterns that use unusual tags in the browser.
Template naming requirement
Only files named _*.tpl.twig (leading underscore) are registered in the template registry by default. The leading underscore marks the file as an embeddable partial rather than a standalone demo page. Override with the templateGlob option if your project uses a different naming convention.