HTML Elements
The Nette\Utils\Html class is a helper for generating HTML code that helps prevent Cross-Site Scripting (XSS) vulnerabilities.
It works by having its objects represent HTML elements; you set their parameters and then render them:
$el = Html::el('img'); // creates <img> element $el->src = 'image.jpg'; // sets src attribute echo $el; // prints '<img src="image.jpg">'
Installation:
composer require nette/utils
All examples assume the following class alias is defined:
use Nette\Utils\Html;
Creating an HTML Element
An element is created using the Html::el()
method:
$el = Html::el('img'); // creates <img> element
Besides the name, you can also specify other attributes using HTML syntax:
$el = Html::el('input type=text class="red important"');
Or pass them as an associative array in the second parameter:
$el = Html::el('input', [ 'type' => 'text', 'class' => 'important', ]);
To change and retrieve the element's name:
$el->setName('img'); $el->getName(); // 'img' $el->isEmpty(); // true, as <img> is a void element
HTML Attributes
Individual HTML attributes can be set and retrieved in three ways; it's up to you which one you prefer. The first is via properties:
$el->src = 'image.jpg'; // sets src attribute echo $el->src; // 'image.jpg' unset($el->src); // removes the attribute // or $el->src = null;
The second way is by calling methods, which, unlike setting properties, can be chained:
$el = Html::el('img')->src('image.jpg')->alt('photo'); // <img src="image.jpg" alt="photo"> $el->alt(null); // removes the attribute
And the third way is the most verbose:
$el = Html::el('img') ->setAttribute('src', 'image.jpg') ->setAttribute('alt', 'photo'); echo $el->getAttribute('src'); // 'image.jpg' $el->removeAttribute('alt');
Attributes can be set in bulk using addAttributes(array $attrs)
and removed using removeAttributes(array $attrNames)
.
The value of an attribute doesn't have to be just a string; boolean values can be used for boolean attributes:
$checkbox = Html::el('input')->type('checkbox'); $checkbox->checked = true; // <input type="checkbox" checked> $checkbox->checked = false; // <input type="checkbox">
An attribute can also be an array of values, which are output separated by spaces. This is useful for CSS classes, for example:
$el = Html::el('input'); $el->class[] = 'active'; $el->class[] = null; // null is ignored $el->class[] = 'top'; echo $el; // '<input class="active top">'
An alternative is an associative array, where the values indicate whether the key should be included:
$el = Html::el('input'); $el->class['active'] = true; $el->class['top'] = false; echo $el; // '<input class="active">'
CSS styles can be written as associative arrays:
$el = Html::el('input'); $el->style['color'] = 'green'; $el->style['display'] = 'block'; echo $el; // '<input style="color: green; display: block">'
We've used properties so far, but the same can be achieved using methods:
$el = Html::el('input'); $el->style('color', 'green'); $el->style('display', 'block'); echo $el; // '<input style="color: green; display: block">'
Or even in the most verbose way:
$el = Html::el('input'); $el->appendAttribute('style', 'color', 'green'); $el->appendAttribute('style', 'display', 'block'); echo $el; // '<input style="color: green; display: block">'
One final detail: the href()
method can simplify the composition of URL query parameters:
echo Html::el('a')->href('index.php', [ 'id' => 10, 'lang' => 'en', ]); // '<a href="index.php?id=10&lang=en"></a>'
Data Attributes
Data attributes have special support. Since their names contain hyphens, accessing them via properties and methods isn't as elegant, so there's a dedicated data()
method:
$el = Html::el('input'); $el->{'data-max-size'} = '500x300'; // not as elegant $el->data('max-size', '500x300'); // is elegant echo $el; // '<input data-max-size="500x300">'
If the value of a data attribute is an array, it is automatically serialized to JSON:
$el = Html::el('input'); $el->data('items', [1,2,3]); echo $el; // '<input data-items="[1,2,3]">'
Element Content
The inner content of the element is set using the setHtml()
or setText()
methods. Use the former only if you are sure that the parameter contains a reliably safe HTML string.
echo Html::el('span')->setHtml('hello<br>'); // '<span>hello<br></span>' echo Html::el('span')->setText('10 < 20'); // '<span>10 < 20</span>'
Conversely, the inner content can be retrieved using the getHtml()
or getText()
methods. The latter removes HTML tags from the content and converts HTML entities back to characters.
echo $el->getHtml(); // '10 < 20' echo $el->getText(); // '10 < 20'
Child Nodes
The inner content of an element can also be an array of child nodes. Each child can be either a string or another Html
object. They are added using addHtml()
or addText()
:
$el = Html::el('span') ->addHtml('hello<br>') ->addText('10 < 20') ->addHtml( Html::el('br') ); // <span>hello<br>10 < 20<br></span>
Another way to create and insert a new Html
node:
$ul = Html::el('ul'); $ul->create('li', ['class' => 'first']) ->setText('first'); // <ul><li class="first">first</li></ul>
You can work with nodes as if they were array elements. That is, access individual nodes using square brackets, count them using count()
, and iterate over them:
$el = Html::el('div'); $el[] = '<b>hello</b>'; $el[] = Html::el('span'); echo $el[1]; // '<span></span>' foreach ($el as $child) { /* ... */ } echo count($el); // 2
A new node can be inserted at a specific position using insert(?int $index, $child, bool $replace = false)
. If $replace = false
, it inserts the element at position $index
and shifts the others. If $index = null
, it appends the element to the end.
// inserts the element at the first position and shifts the others $el->insert(0, Html::el('span'));
All nodes can be retrieved using the getChildren()
method and removed using the removeChildren()
method.
Creating a Document Fragment
If you want to work with an array of nodes without a wrapping element, you can create a document fragment by passing null
instead of an element name:
$el = Html::el(null) ->addHtml('hello<br>') ->addText('10 < 20') ->addHtml( Html::el('br') ); // hello<br>10 < 20<br>
The methods fromHtml()
and fromText()
offer a faster way to create a fragment:
$el = Html::fromHtml('hello<br>'); echo $el; // 'hello<br>' $el = Html::fromText('10 < 20'); echo $el; // '10 < 20'
Generating HTML Output
The simplest way to output an HTML element is to use echo
or cast the object to (string)
. You can also output the opening tag, closing tag, and attributes separately:
$el = Html::el('div class=header')->setText('hello'); echo $el; // '<div class="header">hello</div>' $s = (string) $el; // '<div class="header">hello</div>' $s = $el->toHtml(); // '<div class="header">hello</div>' $s = $el->toText(); // 'hello' echo $el->startTag(); // '<div class="header">' echo $el->endTag(); // '</div>' echo $el->attributes(); // 'class="header"'
An important feature is automatic protection against Cross-Site Scripting (XSS). All attribute values or content inserted via setText()
or addText()
are reliably escaped:
echo Html::el('div') ->title('" onmouseover="bad()') ->setText('<script>bad()</script>'); // <div title='" onmouseover="bad()'><script>bad()</script></div>
Conversion HTML ↔ Text
You can use the static method htmlToText()
to convert HTML to text:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
The Nette\Utils\Html
object implements the Nette\HtmlStringable
interface. Latte and Forms use this interface, for example, to distinguish objects that have a __toString()
method returning HTML code. This prevents double escaping if, for example, you print the object in a template using {$el}
.