PHP markup generation without the fuss

v0.11.10 2021-10-20 14:56 UTC


PHP from Packagist Latest Version Total Downloads Build Status PHPStan License

PHP markup generation without the fuss.


composer require decodelabs/tagged

PHP version

Please note, the final v1 releases of all Decode Labs libraries will target PHP8 or above.

Current support for earlier versions of PHP will be phased out in the coming months.


Tagged uses Veneer to provide a unified frontage under DecodeLabs\Tagged. You can access all the primary HTML functionality via this static frontage without compromising testing and dependency injection.

HTML markup

Generate markup using a simple, flexible interface.

use DecodeLabs\Tagged as Html;

echo Html::{''}('This is element content', [
    'title' => 'This is a title'


<div class="my-class" id="my-id" title="This is a title">This is element content</div>

Create individual tags without content:

use DecodeLabs\Tagged as Html;

$tag = Html::tag('');

echo $tag->open();
echo 'Content';
echo $tag->close();

Wrap HTML strings to be used where an instance of Markup is needed:

use DecodeLabs\Tagged as Html;

$buffer = Html::raw('<span class="test">My span</span>');

Prepare arbitrary input for Markup output:

use DecodeLabs\Tagged as Html;

$markup = Html::wrap(
    function() {
        yield Html::h1('My title');
    [Html::p(['This is ', Html::strong('mixed'), ' content'])]


You can nest elements in multiple ways:

use DecodeLabs\Tagged as Html;

// Pass in nested elements via array
echo Html::div([
    Html::{'span.inner1'}('Inner 1'),
    ' ',
    Html::{'span.inner2'}('Inner 2')

// Return anything and everything via a generator
echo Html::div(function($el) {
    // $el is the root element

    // Nest elements with a single call
    yield Html::{'header > h1'}('This is a header');
    yield Html::p('This is a paragraph');

    // Set attributes inline
    yield Html::{'p[data-target=open]'}('Target paragraph');

    // Generator return values are rendered too
    return Html::{'div.awesome'}('This is awesome!');

Convert to HTML

Parse various formats and convert to HTML:

use DecodeLabs\Tagged as Html;

// Plain text
echo Html::$parse->plainText($plainText); // Replace \n with <br />

// Markdown
echo Html::$parse->markdown($myMarkdown); // Trusted markdown
echo Html::$parse->userMarkdown($myMarkdown); // Untrusted markdown
echo Html::$parse->inlineMarkdown($myMarkdown); // Trusted inline markdown
echo Html::$parse->userInlineMarkdown($myMarkdown); // Untrusted inline markdown

// Tweet
echo Html::$parse->tweet($plainTweet); // Convert tweet source to HTML

Time and date

Format and wrap dates and intervals

use DecodeLabs\Tagged as Html;

// Custom format
Html::$time->format('now', 'd/m/Y', 'Europe/London');

// Locale format
// When timezone is true it is fetched from Systemic::$timezone
Html::$time->locale('now', 'long', 'long', true);

// Locale shortcuts
Html::$time->dateTime('tomorrow'); // medium
// ...etc

// Intervals
Html::$time->since('yesterday'); // 1 day ago
Html::$time->until('tomorrow'); // 1 day from now
Html::$time->sinceAbs('yesterday'); // 1 day
Html::$time->untilAbs('yesterday'); // -1 day
Html::$time->between('yesterday', 'tomorrow'); // 1 day


Create the markup needed for font or SVG icons:

use DecodeLabs\Tagged as Html;

echo Html::$icon->aubergine; // <i class="icon icon-aubergine"></i>

echo Html::$icon->aubergine; // <svg><use xlink:href="#aubergine" /></svg>

echo Html::$icon->aubergine; // <svg><use xlink:href="path/to/my/file.svg#aubergine" /></svg>

Media embeds

Normalize embed codes shared from media sites:

use DecodeLabs\Tagged as Html;

echo Html::$embed->video('');

To text

Convert and normalize html to plain text:

use DecodeLabs\Tagged as Html;

Html::$toText->convert('<h1>My html</h1>'); // My html
Html::$toText->preview('<h1>My html</h1>', 5); // My ht...

XML handling

Looking for the XML stuff that was here?

The XML manipulation functionality of Tagged has been moved to its own project, Exemplar.


Tagged is licensed under the MIT License. See LICENSE for the full license text.