PHPackages                             performing/twig-components - 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. performing/twig-components

ActiveLibrary[Templating &amp; Views](/categories/templating)

performing/twig-components
==========================

Twig components extension

0.7.0(9mo ago)81259.4k↓31%17[6 issues](https://github.com/performingdigital/twig-components/issues)6MITPHPPHP ^8.2CI passing

Since Oct 9Pushed 9mo ago6 watchersCompare

[ Source](https://github.com/performingdigital/twig-components)[ Packagist](https://packagist.org/packages/performing/twig-components)[ Docs](https://github.com/giorgiopogliani/twig-components)[ RSS](/packages/performing-twig-components/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (5)Versions (31)Used By (6)

Twig components extension
=========================

[](#twig-components-extension)

[![Packagist Version](https://camo.githubusercontent.com/60fe37cb69e41bb82e1a948a035a594576b4726f8fcf53c6edbcb36383177926/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f706572666f726d696e672f747769672d636f6d706f6e656e7473)](https://packagist.org/packages/performing/twig-components) [![Tests](https://github.com/giorgiopogliani/twig-components/actions/workflows/run-tests.yml/badge.svg)](https://github.com/giorgiopogliani/twig-components/actions/workflows/run-tests.yml) [![Packagist Downloads](https://camo.githubusercontent.com/8bb009ef1125274a3feb9eadea42fc46ce2c919be72bfd8c7473f9963cbb32e0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f706572666f726d696e672f747769672d636f6d706f6e656e7473)](https://packagist.org/packages/performing/twig-components)

This is a PHP package for automatically create Twig components as tags. This is highly inspired from Laravel Blade Components.

Installation
------------

[](#installation)

You can install the package via Composer:

```
composer require performing/twig-components
```

Configuration
-------------

[](#configuration)

This package should work anywhere where Twig is available.

```
use Performing\TwigComponents\Configuration;

/** @var \Twig\Environment $twig */
Configuration::make($twig)
    ->setTemplatesPath('/relative/directory/to/components') // default is 'components'
    ->setTemplatesExtension('twig') // default is 'twig'
    ->setup();
```

To enable the package just pass your Twig environment object to the function and specify your components folder relative to your Twig templates folder.

### Configuration for Craft CMS

[](#configuration-for-craft-cms)

In Craft CMS you should do something like this:

```
// Module.php
if (Craft::$app->request->getIsSiteRequest()) {
    Event::on(
        Plugins::class,
        Plugins::EVENT_AFTER_LOAD_PLUGINS,
        function (Event $event) {
            $twig = Craft::$app->getView()->getTwig();
            \Performing\TwigComponents\Configuration::make($twig)->setup();
        }
    );
}
```

> The `if` statement ensure you don't get `'Unable to register extension "..." as extensions have already been initialized'` as error.

### Configuration for Symfony

[](#configuration-for-symfony)

In Symfony you can do something like this:

```
# services.yml
services:
    My\Namespace\TwigEnvironmentConfigurator:
        decorates: 'twig.configurator.environment'
        arguments: ['@My\Namespace\TwigEnvironmentConfigurator.inner']
```

```
// TwigEnvironmentConfigurator.php
use Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator;
use Twig\Environment;
use Performing\TwigComponents\Configuration;

final class TwigEnvironmentConfigurator
{
    public function __construct(
        private EnvironmentConfigurator $decorated
    ) {}

    public function configure(Environment $environment) : void
    {
        $this->decorated->configure($environment);
        Configuration::make($environment)
            ->setTemplatesPath('/relative/directory/to/components')
            ->setup();
    }
}
```

### Configuration for October CMS / Winter CMS

[](#configuration-for-october-cms--winter-cms)

In October CMS and Winter CMS you need to hook into `cms.page.beforedisplay` event inside your plugin's boot method in order to access Twig instance.
Then you can use your plugin hint path to choose a `views` subfolder as components' folder.

```
plugins
|__namespace
   |__pluginname
      |__views
         |__components
            |__button.twig

```

```
public function boot(): void
{
    Event::Listen('cms.page.beforeDisplay', function ($controller, $url, $page) {
        $twig = $controller->getTwig();
        Configuration::make($twig)
            ->setTemplatesPath('namespace.pluginname::components', hint: true)
            ->useGlobalContext() // use this to keep Twig context from CMS
            ->setup();
    });
}
```

> All features, like subfolders are supported. For example `` will refer to `plugins/namespace/pluginname/views/forms/input.twig`.

Usage
-----

[](#usage)

Components are just Twig templates in a folder of your choice (e.g. `/components`) and can be used anywhere in your Twig templates:

```
{# /components/button.twig #}

    {{ slot }}

```

> The slot variable is any content you will add between the opening and the close tag.

To reach a component you need to use the dedicated tag `x` followed by `:` and the filename of your component without extension:

```
{# /index.twig #}
{% x:button %}
    Click me
{% endx %}
```

It will render:

```

    Click me

```

### Custom tags

[](#custom-tags)

The same behaviour can be obtained with a **special HTML syntax**.

```
Configuration::make($twig)
    ->setTemplatesPath('/relative/directory/to/components')
    ->useCustomTags()
    ->setup();
```

```
{# /index.twig #}

    Click me

```

### Attributes

[](#attributes)

You can also pass any params like you would using an `include`. The benefit is that you will have the powerful `attributes` variable to merge attributes or to change your component behaviour.

```
{# /components/button.twig #}

    {{ slot }}

{# /index.twig #}
{% x:button with {class: 'text-white'} %}
    Click me
{% endx %}

{# Rendered #}

    Click me

```

With **custom tags** you can pass any attribute to the component in different ways. To interprate the content as Twig you need to prepend the attribute name with a `:`, but it works also in other ways.

```

    Submit

```

### Subfolders

[](#subfolders)

To reach components in subfolders you can use *dot-notation* syntax.

```
{# /components/button/primary.twig #}

    {{ slot }}

{# /index.twig #}
{% x:button.primary %}
    Click me
{% endx %}
```

### Named slots

[](#named-slots)

In case of use of multiple slots you can name them.

```
{# /components/card.twig #}

        {{ title }}

        {{ body }}

```

Use with standard syntax:

```
{# /index.twig #}
{% x:card %}
    {% slot:title with {class: 'text-2xl'} %}Title{% endslot %}
    {% slot:body %}Body{% endslot %}
{% endx %}
```

Use with custom tags syntax:

```
{# /index.twig #}

    Title
    Body

```

### Twig namespaces

[](#twig-namespaces)

In addition to the specified directory, you can also reference components from a Twig namespace by prepending the component name with `:`.

```
// register namespace with Twig templates loader
$loader->addPath(__DIR__ . '/some/other/dir', 'ns');
```

Use with standard syntax:

```
{% x:ns:button with {class: 'bg-blue-600'} %}
    Click me
{% endx %}
```

Use with custom tags syntax:

```

    Click me

```

### Dynamic components

[](#dynamic-components)

Sometimes you may need to render a component but not know which component should be rendered until runtime.
In this situation, you may use the built-in `dynamic-component` to render the component based on a runtime value or variable:

```
{% set componentName = 'button' %}

    Click me

```

Contributing
------------

[](#contributing)

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

53

—

FairBetter than 97% of packages

Maintenance56

Moderate activity, may be stable

Popularity48

Moderate usage in the ecosystem

Community28

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor1

Top contributor holds 84.3% 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

Every ~63 days

Recently: every ~233 days

Total

29

Last Release

279d ago

PHP version history (6 changes)0.0.1PHP ^7.4

0.0.5PHP ^7.3

0.3.2PHP ^7.3|^8.0

0.4.5PHP ^7.2|^8.0

0.5.0PHP ^7.4|^8.0

0.7.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/28866565?v=4)[Giorgio Pogliani](/maintainers/giorgiopogliani)[@giorgiopogliani](https://github.com/giorgiopogliani)

---

Top Contributors

[![giorgiopogliani](https://avatars.githubusercontent.com/u/28866565?v=4)](https://github.com/giorgiopogliani "giorgiopogliani (107 commits)")[![Pindagus](https://avatars.githubusercontent.com/u/2330211?v=4)](https://github.com/Pindagus "Pindagus (5 commits)")[![rasmuswinter](https://avatars.githubusercontent.com/u/1754971?v=4)](https://github.com/rasmuswinter "rasmuswinter (4 commits)")[![kurtrank](https://avatars.githubusercontent.com/u/11091840?v=4)](https://github.com/kurtrank "kurtrank (4 commits)")[![ArnaudLigny](https://avatars.githubusercontent.com/u/80580?v=4)](https://github.com/ArnaudLigny "ArnaudLigny (3 commits)")[![marcomessa](https://avatars.githubusercontent.com/u/4236142?v=4)](https://github.com/marcomessa "marcomessa (2 commits)")[![ryanscherler](https://avatars.githubusercontent.com/u/881938?v=4)](https://github.com/ryanscherler "ryanscherler (1 commits)")[![nevmn](https://avatars.githubusercontent.com/u/34862673?v=4)](https://github.com/nevmn "nevmn (1 commits)")

---

Tags

digitaltwig-components

###  Code Quality

TestsPest

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/performing-twig-components/health.svg)

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

###  Alternatives

[twig/intl-extra

A Twig extension for Intl

36763.2M221](/packages/twig-intl-extra)[rcrowe/twigbridge

Adds the power of Twig to Laravel

9105.9M50](/packages/rcrowe-twigbridge)[twig/cssinliner-extra

A Twig extension to allow inlining CSS

22918.5M55](/packages/twig-cssinliner-extra)[symfony/ux-twig-component

Twig components for Symfony

21914.8M162](/packages/symfony-ux-twig-component)[twig/markdown-extra

A Twig extension for Markdown

12114.3M83](/packages/twig-markdown-extra)[symfony/ux-live-component

Live components for Symfony

1635.6M72](/packages/symfony-ux-live-component)

PHPackages © 2026

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