|
| 1 | +Smart HTML Attributes |
| 2 | +********************* |
| 3 | + |
| 4 | +.[perex] |
| 5 | +Latte 3.1 comes with a set of improvements that focuses on one of the most common activities in templates – printing HTML attributes. It brings more convenience, flexibility and security. |
| 6 | + |
| 7 | + |
| 8 | +Boolean Attributes |
| 9 | +================== |
| 10 | + |
| 11 | +HTML uses special attributes like `checked`, `disabled`, `selected`, or `hidden`, where the specific value is irrelevant—only their presence matters. They act as simple flags. |
| 12 | + |
| 13 | +Latte 3.1 handles them automatically. You can pass any expression to the attribute. If it is truthy, the attribute is rendered. If it is falsey (e.g. `false`, `null`, `0`, or an empty string), the attribute is completely omitted. |
| 14 | + |
| 15 | +This means you can say goodbye to cumbersome macro conditions or `n:attr`: |
| 16 | + |
| 17 | +```latte |
| 18 | +<input type="text" disabled={$isDisabled} readonly={$isReadOnly}> |
| 19 | +</form> |
| 20 | +``` |
| 21 | + |
| 22 | +If `$isReadOnly` is `true` and `$isDisabled` is `false`, it renders: |
| 23 | + |
| 24 | +```latte |
| 25 | +<input type="text" readonly> |
| 26 | +``` |
| 27 | + |
| 28 | +If you need this toggling behavior for standard attributes that don't have this automatic handling (like `data-` or `aria-` attributes), use the [toggle |filters#toggle] filter. |
| 29 | + |
| 30 | + |
| 31 | +Null Values |
| 32 | +=========== |
| 33 | + |
| 34 | +This is one of the most pleasant changes. Previously, if a variable was `null`, it printed as an empty string `""`. This often led to empty attributes in HTML like `class=""` or `title=""`. |
| 35 | + |
| 36 | +In Latte 3.1, a new universal rule applies: **A value of `null` means the attribute does not exist.** |
| 37 | + |
| 38 | +```latte |
| 39 | +<div title="{$title}"></div> |
| 40 | +``` |
| 41 | + |
| 42 | +If `$title` is `null`, the output is `<div></div>`. If it contains a string, e.g. "Hello", the output is `<div title="Hello"></div>`. Thanks to this, you don't have to wrap attributes in conditions. |
| 43 | + |
| 44 | +If you use filters, keep in mind that they usually convert `null` to a string (e.g. empty string). To prevent this, use the [nullsafe operator |filters#Nullsafe Filters] `?|`: |
| 45 | + |
| 46 | +```latte |
| 47 | +<div title="{$title?|upper}"></div> |
| 48 | +``` |
| 49 | + |
| 50 | + |
| 51 | +Classes |
| 52 | +======= |
| 53 | + |
| 54 | +You can pass an array to the `class` attribute, and Latte will automatically join the items with spaces. |
| 55 | + |
| 56 | +This is perfect for conditional classes: if the array is associative, the keys are used as class names and the values as conditions. The class is rendered only if the condition is true. |
| 57 | + |
| 58 | +```latte |
| 59 | +<div class="header"> |
| 60 | + <button class={[ |
| 61 | + btn, |
| 62 | + btn-primary, |
| 63 | + active => $isActive, |
| 64 | + ]}>Press me</button> |
| 65 | +</div> |
| 66 | +``` |
| 67 | + |
| 68 | +If `$isActive` is true, it renders: |
| 69 | + |
| 70 | +```latte |
| 71 | +<div class="header"> |
| 72 | + <button class="btn btn-primary active">Press me</button> |
| 73 | +</div> |
| 74 | +``` |
| 75 | + |
| 76 | +This behavior is not limited to `class`. It works for **any HTML attribute** that expects a space-separated list of values, such as `itemprop`, `rel`, `sandbox`, etc. |
| 77 | + |
| 78 | +```latte |
| 79 | +<a rel={[nofollow, noopener, external => $isExternal]}>link</a> |
| 80 | +``` |
| 81 | + |
| 82 | + |
| 83 | +Styles |
| 84 | +====== |
| 85 | + |
| 86 | +The `style` attribute also supports arrays. It is especially useful for conditional styles. If an array item contains a key (CSS property) and a value, the property is rendered only if the value is not `null`. |
| 87 | + |
| 88 | +```latte |
| 89 | +<div style={[ |
| 90 | + background => lightblue, |
| 91 | + display => $isVisible ? block : null, |
| 92 | + font-size => '16px', |
| 93 | +]}></div> |
| 94 | +``` |
| 95 | + |
| 96 | +If `$isVisible` is false, it renders: |
| 97 | + |
| 98 | +```latte |
| 99 | +<div style="background: lightblue; font-size: 16px"></div> |
| 100 | +``` |
| 101 | + |
| 102 | + |
| 103 | +Data Attributes |
| 104 | +=============== |
| 105 | + |
| 106 | +Often we need to pass configuration for JavaScript into HTML. Previously this was done via `json_encode`. Now you can simply pass an array or object to a `data-` attribute and Latte will serialize it to JSON: |
| 107 | + |
| 108 | +```latte |
| 109 | +<div data-config={[ theme: dark, version: 2 ]}></div> |
| 110 | +``` |
| 111 | + |
| 112 | +Outputs: |
| 113 | + |
| 114 | +```latte |
| 115 | +<div data-config='{"theme":"dark","version":2}'></div> |
| 116 | +``` |
| 117 | + |
| 118 | +Also, `true` and `false` are rendered as strings `"true"` and `"false"` (i.e. valid JSON). |
| 119 | + |
| 120 | + |
| 121 | +Aria Attributes |
| 122 | +=============== |
| 123 | + |
| 124 | +The WAI-ARIA specification requires text values `"true"` and `"false"` for boolean values. Latte handles this automatically for `aria-` attributes: |
| 125 | + |
| 126 | +```latte |
| 127 | +<button aria-expanded={true} aria-checked={false}></button> |
| 128 | +``` |
| 129 | + |
| 130 | +Outputs: |
| 131 | + |
| 132 | +```latte |
| 133 | +<button aria-expanded="true" aria-checked="false"></button> |
| 134 | +``` |
| 135 | + |
| 136 | + |
| 137 | +Type Checking |
| 138 | +============= |
| 139 | + |
| 140 | +Latte 3.1 checks attribute types to prevent you from printing nonsense. |
| 141 | + |
| 142 | +1. **Standard attributes (href, src, id...):** Expect a string or `null`. If they receive an array, object or boolean, Latte throws a warning and the attribute is omitted. |
| 143 | +2. **Boolean attributes (checked...):** Expect a boolean. |
| 144 | +3. **Special attributes (class, style, data-, aria-):** Have their own rules described above. |
| 145 | + |
| 146 | +This check helps you discover bugs in your code early. |
| 147 | + |
| 148 | + |
| 149 | +Migration from Latte 3.0 |
| 150 | +======================== |
| 151 | + |
| 152 | +Since the behavior of `null` changes (it used to print `""`, now it doesn't print anything) and `data-` attributes (booleans used to print `1`/`""`, now `"true"`/`"false"`), Latte offers a tool to help with migration. |
| 153 | + |
| 154 | +You can enable **migration warnings** (see [Develop |develop#Migration Warnings]), which will warn you during rendering if the output differs from Latte 3.0. |
| 155 | + |
| 156 | +If the new behavior is correct (e.g. you want the empty attribute to disappear), confirm it using the `|accept` filter to suppress the warning: |
| 157 | + |
| 158 | +```latte |
| 159 | +<div class="{$var|accept}"></div> |
| 160 | +``` |
| 161 | + |
| 162 | +If you want to keep the attribute as empty (e.g. `title=""`) instead of dropping it, use the null coalescing operator: |
| 163 | + |
| 164 | +```latte |
| 165 | +<div title={$var ?? ''}></div> |
| 166 | +``` |
| 167 | + |
| 168 | +Or, if you strictly require the old behavior (e.g. `"1"` for `true`), explicitly cast the value to string: |
| 169 | + |
| 170 | +```latte |
| 171 | +<div data-foo={(string) $bool}></div> |
| 172 | +``` |
| 173 | + |
| 174 | +Once all warnings are resolved, disable migration warnings and **remove all** `|accept` filters from your templates, as they are no longer needed. |
0 commit comments