Latte 3.1: Semantic HTML Generation and Type Safety for PHP Templates

Web Development

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 null value assigned to any HTML attribute will cause its complete removal from the rendered output.
  • Impact: This eliminates the need for n:attr or {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:attr is 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 __toString method into title? 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:

  1. Strict types: If the upper filter expects a string but receives null, a TypeError will now occur (whereas previously, a silent conversion to an empty string might have happened).
  2. Loss of "Smart" behavior: Even if the filter somehow accepted null, it would likely return an empty string "". For Latte, "" is no longer null, meaning the title attribute would render as title="" 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 using n:attributes is 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:

  1. Call $latte->setMigrationWarnings().
  2. Browse through your application. Latte will log (e.g., to Tracy) exactly where the output differs from version 3.0.
  3. Use the temporary |accept filter 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.