PHPackages                             hiraeth/twig-tags - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. hiraeth/twig-tags

ActiveOpus-package[Templating &amp; Views](/categories/templating)

hiraeth/twig-tags
=================

Provides Tag Components for Hiraeth Twig

3.0-beta(4mo ago)1280↓87.5%1MITPHPPHP &gt;=8.2

Since Mar 5Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/hiraeth-php/twig-tags)[ Packagist](https://packagist.org/packages/hiraeth/twig-tags)[ RSS](/packages/hiraeth-twig-tags/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (5)Versions (2)Used By (1)

Twig Tags
=========

[](#twig-tags)

Provides component-like tags for Twig in the [Hiraeth Nano Framework](https://hiraeth.dev).

Introduction
------------

[](#introduction)

This package is designed to solve one problem and solve it well. Specifically, it is designed to enable you to create and use component-like templates in Twig. The main reason you'd probably want to do this is if you're using something like Tailwind and you want to avoid writing traditional CSS classes/selectors and relying on `@apply`. The only other present-day workaround to do something similar would be potentially writing extremely repetitive and verbose {% include %} tags. Even then, there are limitations. For example, there's no way to easily provide child components to a given included component in the parent scope, so you'd have to have a large set of extremely specialized components or a ton of dynamic logic inside a single included component to handle different types of data provided to it.

To solve this, Twig Tags takes advantage of Hiraeth 3.0 beta's new Renderer interface (for Twig extensions). This provides post-processing modification of Twig templates. From Twig's perspective, your components are just another HTML Tag, but after your template renders, the post-processing swaps those tags for their respective components using attributes similar to React props for a fully context aware solution.

The Problem
-----------

[](#the-problem)

Let's imagine a simple example. You want to make a button component so that you can add a button-style links to your markup. Traditionally, you'd just use markup:

```
My Resource
```

That's *relatively* fine if you have standard CSS with class selectors. You can litter tens, hundreds, or even thousands of these around your Twig templates. Then if you need to update the style of a button, you just go into your CSS, find the `.button` selector, and away you go.

Enter Tailwind. You want to use Tailwind. So, your go-to solution is going to be to just modify your CSS to use the `@apply` directive:

```
.button {
    @apply ;
}
```

This works, but as things get increasingly complex, you start to realize `@apply` isn't always working like it would if those classes were added directly on the element. Much of this is what led Tailwind's creator, Adam Wathan, to write "I can say with absolute certainty that if I started Tailwind CSS over from scratch, there would be no @apply." It's also why `@apply` usage is heavily frowned upon.

OK... no problem... Twig to the rescue. Let's move our button into its own file `components/button.html`:

```
{{ text }}
```

...and then we'll just use `{% include ... %}` like so:

```
{% include 'components/button.html' with {href: "/route/to/resource", text: "My Resource"} %}
```

While this works, there are a lot of drawbacks. Firstly, the syntax for `{% include %}` is extremely verbose. Secondly, what happens if you have a more complex component, like a grid component where the contents of each cell in the grid need to be defined in the parent scope? What if you need to use components within components? You can start to see pretty easily how your daily development experience is no longer going to be working with relatively simple to parse HTML, but a complex stack of includes with sparsely embedded HTML, properties and conditions to control child element types, and generally all sorts of madness.

The Solution
------------

[](#the-solution)

To demonstrate the abilities of Twig Tags, let's just go ahead an install it.

```
composer require hiraeth/twig-tags

```

Now we'll create two new components. Firstly `resources/tags/atoms/title.html`:

```
{{ value }}
```

Secondly, a grid (`resources/tags/layout/grid.html`) :

```
{% if title|default(null) %}

{% endif %}

   {% for child in children %}

           {{ child|raw }}

   {% endfor %}

```

Note, in the above grid, we're doing a few interesting things.

Firstly, we're including our `title` component. Components can easily include sub-components. Secondly, we're passing the dynamic value of the incoming `title` attribute. This syntax for dynamic values supports any twig expression. Accordingly, attributes can have object values, or can be any valid Twig expression, e.g. `{% v: 2 * 2 %}`.

Secondly, we're looping over the original children from the parent scope to determine the contents of our grid, placing each child in the appropriate wrapper with a `col-span`, thereby keeping our Tailwind layout nicely encapsulated in our component, while the content can be defined elsewhere.

Lastly, we're using the incoming `split` attribute to determine, dynamically, what our `col-span` value will be. Passing `split="2"` will therefore result in a 50/50 split with each column spanning 6 columns, while `split="4"` would result in 25/25/25/25 with each item spanning 3 columns.

Finally, let's see how we use our grid component (and by extension our title component) in our main template:

```

    First Child
    Second Child

```

Simple!

Caveats
-------

[](#caveats)

OK, there's always a few. But we promise, there's not that many:

1. The extension of your templates must be `.html` and `.htm` and your tags must have the same extension as the file they're included in. This is probably already the case if you're using Hiraeth cause you're not a heathen. Other formats may be supported down the line, but currently it explicitly looks for `.html` or `.htm` and the tag component extensions must match the template extension.
2. Lastly, due to HTML not really supporting XML namespaces, you cannot have tag components directly in `resources/tags`. They **MUST** be in a sub-directory. When the tag `` is used, the first part of the tag name is stripped, the rest is translated to the path to the component. In that respect `` would work just as well... but if you only have two levels, the first part will be dropped and the post-processor will not recognize it as a tag component.

That's it!

Development
-----------

[](#development)

#### Code Check and Testing

[](#code-check-and-testing)

Run Analysis:

```
php vendor/bin/phpstan -l7 analyse src/

```

Run Tests:

```
php vendor/bin/phpunit --bootstrap vendor/autoload.php test/cases

```

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance78

Regular maintenance activity

Popularity13

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

120d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4ab2b91daf2aa6e4c7f98f785a3135daa3e9998bd7021d89df05a374e28ecde5?d=identicon)[mattsah](/maintainers/mattsah)

---

Top Contributors

[![mattsah](https://avatars.githubusercontent.com/u/586346?v=4)](https://github.com/mattsah "mattsah (36 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/hiraeth-twig-tags/health.svg)

```
[![Health](https://phpackages.com/badges/hiraeth-twig-tags/health.svg)](https://phpackages.com/packages/hiraeth-twig-tags)
```

###  Alternatives

[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45444.2k1](/packages/pressbooks-pressbooks)[drupal/core

Drupal is an open source content management platform powering millions of websites and applications.

21866.0M1.7k](/packages/drupal-core)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[silverstripe/framework

The SilverStripe framework

7313.7M2.8k](/packages/silverstripe-framework)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6942.5M421](/packages/drupal-core-recommended)[code16/sharp

Laravel Content Management Framework

79164.7k8](/packages/code16-sharp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
