Latte 3.1: When a templating system truly understands HTML

3 hours ago by David Grudl  

Latte has long held the position of the safest templating system for PHP. It's not just a marketing phrase – it's a consequence of the fact that Latte (unlike Twig or Blade) understands context. It doesn't just distinguish between “HTML” and “PHP code”. It sees tags, attributes, values. And in version 3.1, we pushed this understanding to a level that will radically improve your DX.

While version 3.0 brought a completely new compiler and parser, version 3.1 focuses on semantics and code cleanliness. It comes with the concept of Smart HTML Attributes, which eliminates dozens of lines of unnecessary conditions and helpers.

Let's look at what Latte 3.1 does under the hood and why you'll want to use it.

Native mapping of PHP types to HTML attributes

Until now, the template was a passive string generator. If you sent null to <span title="{$title}">, you got an empty string title="". If you sent an array, you got title="Array". Latte 3.1 changes the rules of the game and introduces strict rendering logic based on data types.

Null means “attribute does not exist”

In the DOM, there is a difference between <div title=""> (empty title) and <div> (no title). Latte 3.1 respects this difference.

  • Behavior: A null value in any HTML attribute results in its complete removal from the output.
  • Impact: The end of n:attr or {if} conditions inside tags. You just pass data.

Boolean attributes without magic

Attributes like disabled, checked or required are binary. Either they are there, or not. Latte now accepts an expression directly in the attribute value.

  • Behavior: Truthy expression ⇒ attribute is rendered. Falsey expression ⇒ attribute disappears.
  • Advantage: n:attr is a great tool, but for this common use-case it was “overkill”. Now the syntax is clean and declarative:
<input disabled={$isDisabled}>

Arrays in class and style

Attributes that expect a list of values (class, rel, sandbox…) now natively accept arrays. Latte handles the intelligent rendering.

<div class={[
    btn,
    btn-primary => $isPrimary, // added only if true
]}></div>

<div style={[
	background => lightblue,
	display => $isVisible ? block : null,
	font-size => '16px',
]}></div>

Automatic JSON serialization

You can pass an array or object (stdClass) to data-* attributes. Latte detects the context and automatically performs json_encode.

WAI-ARIA compliance without effort

Accessibility is important, but the WAI-ARIA specification has its specifics. Unlike standard HTML boolean attributes, where mere presence decides, ARIA requires explicit text values "true" and "false".

Latte 3.1 solves this problem for you. It detects the aria- prefix and automatically ensures correct stringification.

<button aria-expanded={$isExpanded} aria-hidden={=false}>
{* <button aria-expanded="true" aria-hidden="false"> *}

Advantage: No more manual writing of ternary operators like {$val ? 'true' : 'false'}. Latte guarantees valid output.

Type safety in templates

Latte 3.1 is stricter. And that is good. Common templating systems allow you to print an array into href, generating a broken link <a href="Array">.

Latte 3.1 introduces Runtime Type Checking for attributes.

  • Trying to print a boolean into href? Warning.
  • Trying to print an object without __toString into title? Warning.

Thanks to this, you detect errors in presentation logic immediately during development, not when a user complains about broken UI. Moreover, the warning contains the exact line and column in the template.

Strict Types by Default

We are keeping up with the times. The PHP ecosystem has matured to strict_types=1 and Latte is not lagging behind. All templates in Latte 3.1 are compiled with this directive by default. This ensures consistent behavior with your backend code and prevents unwanted type casting in critical template logic.

Nullsafe filters: The Holy Grail for Strict Types

You might be wondering how filters, strict types, and HTML attributes are related. In Latte 3.1, very closely.

Imagine a situation where you want to print a title in uppercase, but the variable might be null.

<div title={$title|upper}>

If $title === null, you encounter two problems:

  1. Strict types: If the upper filter expects a string but receives null, a silent conversion to an empty string would have occurred previously, but with active strict types, a TypeError occurs.
  2. Loss of “Smart” behavior: Even if the filter accepts null, it returns an empty string "", which for Latte is no longer null. The result is <div title="">. The attribute does not disappear, it is just empty.

The solution is the new Nullsafe filter operator ?|.

It works exactly like ?-> in PHP. If the input value is null, the filter is not called at all (nor following filters) and the expression returns null.

<div title={$title?|upper}>

Result? No TypeError, because the filter is not called on null. And the Smart Attribute works, so title completely disappears from the HTML.

Syntactic sugar for cleaner code

We heard the community's call and added missing pieces of syntax:

  • n:elseif: The missing link in chaining conditions using n:attributes is finally here.
  • n:attributes: Alternative syntax <div n:if={$cond}>, thanks to which you can freely use single and double quotes inside {...}.

How to upgrade safely?

Changing the behavior of null and boolean attributes is a BC break, but we thought about that. Latte 3.1 includes a Migration Mode.

  • Call $latte->setMigrationWarnings().
  • Click through the application. Latte will print exactly those places where the output differs from version 3.0 to Tracy/log.
  • Use the temporary |accept filter to confirm that the new behavior (e.g. disappearance of an empty attribute) is desired, or modify the code.

Latte 3.1 is not just “another version”. It is a shift towards modern, type-safe, and semantic HTML generation. Try it out and see how much cleaner your templates can be.

👉 Complete migration guide and documentation

David Grudl Programmer, blogger, and AI evangelist who created the Nette Framework powering hundreds of thousands of websites. He explores artificial intelligence on Uměligence and web development on phpFashion. Weekly, he hosts Tech Guys and teaches people to master ChatGPT and other AI tools. He's passionate about transformative technologies and excels at making them accessible to everyone.