Latte 3.1: Semantic HTML Generation and Type Safety for PHP Templates
Discover Latte 3.1's groundbreaking features, including Smart HTML Attributes, native PHP type mapping to HTML, runtime type checking, and nullsafe filters, enhancing developer experience and template safety for PHP.
Latte has long been recognized as the safest templating system for PHP. This isn't merely a marketing claim; it's a direct result of Latte's deep contextual understanding, distinguishing it from systems like Twig or Blade. Latte doesn't just differentiate between "HTML" and "PHP code"; it comprehends tags, attributes, and values. With version 3.1, this understanding has been further advanced, promising a radical improvement in your Developer Experience (DX).

While version 3.0 introduced a completely new compiler and parser, Latte 3.1 focuses on semantics and code cleanliness. It brings the innovative concept of Smart HTML Attributes, designed to eliminate dozens of lines of unnecessary conditional logic and helper functions. Let's delve into what Latte 3.1 accomplishes under the hood and why it will become an indispensable tool.
Native Mapping of PHP Types to HTML Attributes
Previously, a template functioned as a passive string generator. Sending null to <span title="{$title}"> would result in an empty title="", and an array would yield title="Array". Latte 3.1 fundamentally alters these rules, introducing strict rendering logic based on data types.
Null Means "Attribute Does Not Exist"
In the DOM, there's a crucial distinction between <div title=""> (an empty title) and <div> (no title at all). Latte 3.1 respects this difference.
- Behavior: A
nullvalue assigned to any HTML attribute will cause its complete removal from the rendered output. - Impact: This eliminates the need for
n:attror{if}conditions directly within tags. You simply pass your data.
Boolean Attributes Without Magic
Attributes like disabled, checked, or required are binary: they are either present or absent. Latte now directly accepts an expression as the attribute's value.
- Behavior: A truthy expression renders the attribute. A falsey expression makes the attribute disappear.
- Advantage: While
n:attris powerful, it was often "overkill" for this common use case. Now, the syntax is clean and declarative:<input disabled={$isDisabled}>.
Arrays in class and style
Attributes that expect a list of values, such as class, rel, or sandbox, now natively accept arrays. Latte intelligently handles their 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 now pass arrays or objects (stdClass) directly to data-* attributes. Latte automatically detects the context and performs json_encode.
WAI-ARIA Compliance Without Effort
Accessibility is paramount, but the WAI-ARIA specification has specific requirements. Unlike standard HTML boolean attributes where mere presence decides, ARIA attributes require explicit string values: "true" and "false".
Latte 3.1 solves this for you. It detects the aria- prefix and automatically ensures correct stringification.
<button aria-expanded={$isExpanded} aria-hidden={=false}>
{* renders as: <button aria-expanded="true" aria-hidden="false"> *}
- Advantage: No more manual ternary operators like
{$val ? 'true' : 'false'}. Latte guarantees valid ARIA output.
Type Safety in Templates
Latte 3.1 introduces stricter rules, which is a positive development. Common templating systems often allow printing an array into an href, resulting in a broken link like <a href="Array">.
Latte 3.1 features Runtime Type Checking for attributes:
- Attempting to print a boolean into
href? A warning is issued. - Attempting to print an object without a
__toStringmethod intotitle? A warning is issued.
This ensures that errors in your presentation logic are detected immediately during development, rather than after users report a broken UI. Furthermore, the warning includes the exact line and column within the template.
Strict Types by Default
Keeping pace with modern PHP development, where strict_types=1 is common, Latte 3.1 compiles all templates 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 wonder how filters, strict types, and HTML attributes intertwine. In Latte 3.1, they are very closely related.
Consider a scenario where you want to display a title in uppercase, but the variable might be null:
<div title={$title|upper}>
If $title === null, two issues arise:
- Strict types: If the
upperfilter expects astringbut receivesnull, aTypeErrorwill now occur (whereas previously, a silent conversion to an empty string might have happened). - Loss of "Smart" behavior: Even if the filter somehow accepted
null, it would likely return an empty string"". For Latte,""is no longernull, meaning thetitleattribute would render astitle=""instead of disappearing completely.
The solution is the new Nullsafe filter operator ?|. It functions precisely like PHP's ?->. If the input value is null, the filter (and any subsequent filters in the chain) is not called at all, and the expression returns null.
<div title={$title?|upper}>
Result: No TypeError because the filter isn't invoked on null. And thanks to the Smart Attribute behavior, the title attribute completely disappears from the HTML.
Syntactic Sugar for Cleaner Code
Responding to community feedback, several missing syntax elements have been added:
n:elseif: The long-awaited missing link for chaining conditions usingn:attributesis finally here.n:attributes: An alternative syntax like<div n:if={$cond}>, which allows for free use of single and double quotes inside{...}expressions.
How to Upgrade Safely?
Changing the behavior of null and boolean attributes represents a BC (Backward Compatibility) break, but this has been addressed. Latte 3.1 includes a Migration Mode:
- Call
$latte->setMigrationWarnings(). - Browse through your application. Latte will log (e.g., to Tracy) exactly where the output differs from version 3.0.
- Use the temporary
|acceptfilter to confirm that the new behavior (e.g., the disappearance of an empty attribute) is desired, or modify your code as needed.
Latte 3.1 is more than just another version; it's a significant shift towards modern, type-safe, and semantic HTML generation. Try it out and experience how much cleaner your templates can become.
👉 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.